Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProcesosAgilesUMSS/sansistore/llms.txt

Use this file to discover all available pages before exploring further.

Once a buyer confirms their cart, SansiStore creates an order record in Firestore and begins tracking it through a multi-stage lifecycle. The order history dashboard at /mis-pedidos gives buyers a live view of all their purchases, lets them confirm delivery reception, and provides access to return requests — all protected by the comprador role guard.

Order History Dashboard (/mis-pedidos)

The /mis-pedidos page renders <MyOrdersDashboard> (src/features/orders/components/MyOrdersDashboard.tsx), which is wrapped in a <RouteGuard> requiring the comprador role. The component subscribes to the buyer’s orders in real time via subscribeToMyOrders() and fetches return requests with getMyReturns().
// src/pages/mis-pedidos.astro
<RouteGuard client:load allowedRoles={['comprador']} roleName="Comprador">
  <MyOrdersDashboard client:load />
</RouteGuard>
The dashboard header shows three summary counters:
CounterValue
PedidosTotal order count
ActivosOrders in CREADO, ASIGNADO, RESERVADO, PENDIENTE, EMPAQUETADO, LISTO, or EN CAMINO
DevolucionesTotal return request count
A tab bar switches between the Pedidos list (rendered by <OrderList>) and the Devoluciones list (rendered by <ReturnCard> items).

Real-Time Delivery Notification

When an order’s status transitions to ENTREGADO (or deliveryStatus becomes DELIVERED) while the buyer has the page open, a toast notification slides in from the top-right corner:
✅ Tu pedido fue entregado
   Pedido 3dg-zjs
This is driven by tracking the previous delivery state across subscribeToMyOrders() snapshots using a Map<orderId, wasDelivered> ref.

Order Detail Page (/mis-pedidos/[id])

Clicking any order card navigates to /mis-pedidos/[id], which renders <MyOrderDetailView>. The detail view shows:
  • Order ID (friendly label from parseOrderId())
  • Delivery address and location
  • All orderItems (product name, unit price, quantity, subtotal)
  • Order total
  • Status badges for order status, payment status, and delivery status
  • Buyer reception confirmation button (when status is ENTREGADO)
  • Return request initiation (via createReturnRequest())

Order Lifecycle

Orders progress through a set of statuses defined in OrderStatus (src/features/orders/types.ts). The primary buyer-visible flow is:
1

CREADO

Order is placed by the buyer. Stock is reserved (stockReserved += quantity) in the inventory collection. A payments document is created with status: 'PENDIENTE'.
2

RESERVADO

A seller has claimed the order and begun preparation. stockAvailable is decremented for each item.
3

EMPAQUETADO / LISTO

The order has been packed and is ready for courier pickup.
4

ASIGNADO / EN CAMINO

A courier has accepted and is en route to the delivery address.
5

ENTREGADO

The courier has delivered the order. The buyer can confirm reception, which transitions the order to COMPLETADO and sets buyerReceptionConfirmed: true.
6

PAGADO

Payment has been validated by the seller. Inventory is permanently decremented (stockTotal -= quantity, stockReserved -= quantity).

Status Reference

The initial status set by createOrder(). The order exists in Firestore and stock has been reserved, but no seller has claimed it yet.
Set by reserveOrder(). The seller has accepted the order; stockAvailable is reduced transactionally. The buyer’s order card updates in real time.
The order is placed but awaiting seller review or action. Treated as an active order in buyer dashboard counters.
The order has been prepared and packed, awaiting courier assignment.
Set by readyOrder(). The courier can now pick up the order from the seller.
The order is packed and ready but no courier has been assigned yet. Intermediate state between LISTO and ASIGNADO.
A delivery has been created and assigned to a courier. The courier has accepted the delivery.
The courier is actively delivering the order to the buyer’s address.
The courier has marked the delivery as completed. The buyer sees a toast notification and can confirm reception.
Set by cancelOrder(). Requires an incidentReason string. Stock is restored transactionally: stockAvailable += quantity, stockReserved -= quantity.
The courier could not complete the delivery. An incidentReason and optional incidentNotes are recorded.
The buyer initiated a return after delivery. Set by returnOrder().
Set by rejectOrder(). Requires an incidentReason.
Set by paidOrder() after the seller confirms receipt of payment. stockTotal and stockReserved are decremented in a transaction. Only delivered orders can be moved to this status.
Terminal state for fully resolved orders.
Tracked separately from order status. Values: PENDIENTE (awaiting payment), PAGADO (payment confirmed by seller). Stored both on the orders document and the linked payments document.
Set by the delivery service. Values include DELIVERED, delivered, and custom courier-set states. Checked alongside status === 'ENTREGADO' to determine buyer reception eligibility.

Real-Time Subscription

subscribeToMyOrders() opens a Firestore onSnapshot listener scoped to the authenticated buyer:
// src/features/orders/services/ordersService.ts
export function subscribeToMyOrders(
  userId: string,
  onUpdate: (orders: Order[]) => void,
  onError?: (error: Error) => void
): Unsubscribe {
  const q = query(
    collection(db, 'orders'),
    where('buyerId', '==', userId),
    orderBy('createdAt', 'desc')
  );
  return onSnapshot(q, async (querySnapshot) => {
    const orders = await processQuerySnapshot(querySnapshot);
    onUpdate(orders);
  }, onError);
}
processQuerySnapshot() performs parallel fetches of related locations, users, and deliveries documents, then fetches each order’s orderItems subcollection, resulting in fully hydrated Order objects.

Firestore Data Model

orders collection

FieldTypeDescription
orderIdstringUUID v7 + z-base-32 label (document ID)
secretstring4-digit PIN for anonymous order lookup
buyerIdstringFirebase Auth UID of the buyer
sellerIdstring | nullUID of the seller who claimed the order
customerNamestringBuyer’s display name at time of order
customerPhonestringBuyer’s phone number
addressstringlabel from the selected Location document
statusOrderStatusCurrent order status (see status reference above)
totalnumberTotal order amount in Bolivianos
locationIdstringReference to locations collection
paymentStatusstringPENDIENTE or PAGADO
deliveryStatusstring | nullSet by the delivery/courier service
paymentIdstringSame as orderId; used as payments document ID
incidentReasonstring | nullRequired for CANCELADO / RECHAZADO / NO ENTREGADO
incidentNotesstring | nullOptional extra detail for incidents
buyerReceptionConfirmedbooleanSet true when buyer confirms delivery
createdAtTimestampOrder creation time
updatedAtTimestampLast modification time

orders/{orderId}/orderItems subcollection

FieldTypeDescription
itemIdstringUUID v7 (document ID)
productIdstringReference to products collection
productNamestringProduct name captured at order time
unitPricenumberPrice per unit at time of order
quantitynumberNumber of units ordered
subtotalnumberunitPrice × quantity, rounded to 2 decimal places

returns collection

interface ReturnRequest {
  id?: string;
  orderId: string;
  buyerId: string;
  productId?: string;
  productName?: string;
  items?: ReturnItem[];     // array of { productId, productName, quantity }
  reason: string;
  description?: string;
  status: 'pending_review' | 'approved' | 'rejected';
  createdAt: Timestamp;
}
Return reasons recognized by the system:
KeyLabel
damagedProducto dañado
wrong_productProducto incorrecto
unwantedNo deseado
otherOtro

Returns Page (/my-returns)

The <MyReturnsView> component displays return requests fetched from getMyReturns():
// src/features/orders/services/ordersService.ts
export async function getMyReturns(userId: string): Promise<ReturnRequest[]> {
  const q = query(
    collection(db, 'returns'),
    where('buyerId', '==', userId),
    orderBy('createdAt', 'desc')
  );
  // ...
}
Each return is rendered in a <ReturnCard> showing the order ID, reason, description, and current review status (pending_review, approved, or rejected).
Return requests can only be initiated for orders with status === 'ENTREGADO' or deliveryStatus === 'DELIVERED'. The Confirmar recepción action must be completed before initiating a return.

End-to-End Tests

Order pages are covered by Playwright tests in tests/orders/my-orders.spec.ts:
Mis pedidos - comprador (Ana Mamani)  [serial]
  ✓ el menu lleva a Mi Perfil y de ahi a Mis pedidos
      — /mi-perfil → "Ver mis compras" link → /mis-pedidos
  ✓ muestra el encabezado y las tarjetas de pedidos de Ana
      — heading "Mis pedidos y devoluciones" visible
      — failed order card visible with "No entregado" status and address
      — two additional order links visible by known order IDs

Build docs developers (and LLMs) love