Functions are in src/services/orders.service.ts. The service imports loyalty logic from src/lib/domain/loyalty and src/services/loyalty.service.ts.
Types
OrderItem
interface OrderItem {
product_id : string ;
variant_id ?: string | null ;
variant_name ?: string | null ;
name : string ;
price : number ;
quantity : number ;
image ?: string ;
section ?: string ;
}
OrderRecord
interface OrderRecord {
id : string ;
order_number : string ; // Auto-generated by DB trigger
customer_id : string ;
items : OrderItem [];
subtotal : number ;
shipping_cost : number ;
discount : number ;
total : number ;
status : string ;
payment_method : string ;
payment_status : string ;
shipping_address_id : string | null ;
billing_address_id : string | null ;
tracking_notes : string | null ;
whatsapp_sent : boolean ;
whatsapp_sent_at : string | null ;
created_at : string ;
updated_at : string ;
}
CreateOrderData
interface CreateOrderData {
customer_id : string ;
items : OrderItem [];
subtotal : number ;
shipping_cost ?: number ; // defaults to 0
discount ?: number ; // defaults to 0
total : number ;
payment_method : 'cash' | 'transfer' | 'card' | 'mercadopago' | 'whatsapp' ;
shipping_address_id ?: string ;
billing_address_id ?: string ;
tracking_notes ?: string ;
earned_points ?: number ; // override auto-calculated loyalty points
}
createOrder()
export async function createOrder (
data : CreateOrderData
) : Promise < OrderRecord >
Creates a new order and automatically triggers loyalty point accrual. After the DB insert, calls calculateLoyaltyPoints(data.total) (unless earned_points is provided) and then addLoyaltyPoints(). Loyalty failures are logged but do not throw — the order is always returned.
Full order payload. UUID of the authenticated customer.
Array of purchased items.
Pre-discount, pre-shipping total.
One of 'cash', 'transfer', 'card', 'mercadopago', 'whatsapp'.
Override the auto-calculated loyalty points. If omitted, calculated at 10 points per $100 MXN.
The complete order record as stored in the database.
import { createOrder } from '@/services' ;
const order = await createOrder ({
customer_id: 'user-uuid' ,
items: [
{
product_id: 'prod-uuid' ,
name: 'Aegis Legend 2' ,
price: 1299 ,
quantity: 1 ,
}
],
subtotal: 1299 ,
total: 1299 ,
payment_method: 'whatsapp' ,
});
console . log ( order . order_number ); // e.g. "ORD-0042"
getCustomerOrders()
export async function getCustomerOrders (
customerId : string
) : Promise < OrderRecord []>
Returns all orders for a customer, ordered by created_at DESC.
const orders = await getCustomerOrders ( 'user-uuid' );
getOrderById()
export async function getOrderById (
id : string
) : Promise < OrderRecord | null >
Fetches a single order by primary key. Returns null for not-found (PGRST116) instead of throwing.
const order = await getOrderById ( 'order-uuid' );
getOrderNotificationDetails()
export async function getOrderNotificationDetails (
orderId : string
) : Promise < RealtimeOrderEvent | null >
Fetches enriched data for Social Proof toast notifications. Joins customer_profiles and addresses to produce a RealtimeOrderEvent containing the customer name, city, first product name, and product image.
interface RealtimeOrderEvent {
id : string ;
customer_name : string ;
city : string ;
product_name : string ;
product_image : string ;
}
markWhatsAppSent()
export async function markWhatsAppSent (
orderId : string
) : Promise < void >
Sets whatsapp_sent = true and records whatsapp_sent_at as the current ISO timestamp on the order.
await markWhatsAppSent ( 'order-uuid' );
calculateLoyaltyPoints()
Imported from src/lib/domain/loyalty. The rate is 10 points per $100 MXN spent.
import { calculateLoyaltyPoints } from '@/lib/domain/loyalty' ;
calculateLoyaltyPoints ( 1299 ); // → 129 points
addLoyaltyPoints() — from loyalty.service.ts
export async function addLoyaltyPoints (
customerId : string ,
points : number ,
orderId : string ,
description : string
) : Promise < void >
Calls the process_loyalty_points Supabase RPC function. Errors are logged but not re-thrown to avoid blocking the order flow.
Points to add (positive integer).
Human-readable description, e.g. "Compra #ORD-0042".
getPointsBalance() — from loyalty.service.ts
export async function getPointsBalance (
customerId : string
) : Promise < number >
Calls the get_customer_points_balance Supabase RPC function. Returns 0 on error rather than throwing.
Current V-Coins balance. Returns 0 if the RPC fails.
// Direct service call
const balance = await getPointsBalance ( 'user-uuid' );
// Via hook (preferred in components)
import { usePointsBalance } from '@/hooks/useOrders' ;
const { data : points } = usePointsBalance ( user ?. id );
The underlying RPC call:
-- Supabase RPC
SELECT get_customer_points_balance( 'user-uuid' );