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.

SansiStore’s analytics module consolidates multiple report surfaces within the admin area. Rather than a single dashboard, each report type is an independent panel driven by its own Firestore service or server-side API route. All endpoints require a valid admin Bearer token and return JSON. The sections below describe each report panel, its data source, and the shape of data it exposes.
The SalesReport component visualises revenue over time using getSalesByDateRange from salesService.ts. It queries the orders collection filtered by createdAt within the selected date range and groups results into completed vs. cancelled buckets.Completed statuses (generate revenue): ENTREGADO, COMPLETADO, PAGADO
Cancelled statuses: CANCELADO, NO ENTREGADO
The service returns a SalesSummary object:
interface SalesSummary {
  totalOrders: number;       // All orders in range (all statuses)
  totalIncome: number;       // Sum of `total` for completed orders only
  completedOrders: number;   // Count of completed orders
  cancelledOrders: number;   // Count of cancelled orders
  orders: SaleOrder[];       // Per-order detail
}
To inspect the full timeline for a specific order (buyer, seller, items, payment, and delivery records), use the separate GET /api/admin/order_history?orderId=<id> endpoint available under the Orders section.
The TopSellingProducts component fetches the bestseller ranking from GET /api/admin/top_products. Products are ordered by soldCount descending from the products collection (filtered to active == true). Category names are resolved via a parallel categories collection query.Query parameters:
ParameterDefaultMaxDescription
limit1050Number of products to return
categoryIdFilter to a specific category
Response shape:
{
  "products": [
    {
      "productId": "prod_abc123",
      "name": "Empanada de queso",
      "categoryId": "cat_001",
      "categoryName": "Pastelería",
      "price": 5.00,
      "offerPrice": 4.00,
      "hasOffer": true,
      "imageUrl": "https://storage.example.com/product.jpg",
      "soldCount": 342
    }
  ],
  "total": 1
}
The useTopProducts hook (ventas/top-products/hooks/useTopProducts.ts) wraps getTopProducts from topProductServices.ts and manages loading/error state for the UI component.
The DemandPanel component calls getDemandByHour from demandService.ts. It queries orders by createdAt range, counts orders per hour of day, and returns a DemandSummary:
interface DemandSummary {
  byHour: { hour: number; count: number; label: string }[];  // 24 entries (00:00–23:00)
  totalOrders: number;
  peakHour: number;    // Hour index (0–23) with most orders
  minHour: number;     // Hour index with fewest orders (non-zero)
  avgPerHour: number;  // Average orders per hour (1 decimal)
  top5: { hour: number; count: number }[];
}
An optional categoryId filter (passed as DemandFilterInput.categoryId) narrows the analysis to orders whose items belong to a specific category. Passing 'todas' returns the full dataset.
The CancelledOrdersReport component uses getCancelledOrdersByPeriod and getCancelledOrdersSummary from cancelledOrdersService.ts.Period options: 'day' (today), 'week' (last 7 days), 'month' (current month from the 1st). Custom date ranges are also accepted via startDate / endDate.The service returns CancelledOrder[]:
interface CancelledOrder {
  orderId: string;
  cancelledAt: Date;       // Falls back to updatedAt if cancelledAt is null
  customerName: string;
  total: number;
  incidentReason: string | null;
}
The summary endpoint getCancelledOrdersSummary returns:
interface CancelledOrdersSummary {
  totalCancelled: number;
  cancellationPercentage: number;  // % of all orders that are cancelled
}
The MessengerPerformancePage surface is powered by messengerPerformanceService.ts. It reads the deliveries Firestore collection (statuses delivered / DELIVERED) and correlates deliveries to couriers via the courierId field.Two functions are exposed:getMessengerPerformanceByDay(messengerId, date) — Returns a MessengerPerformanceReport for a single courier on a given day:
interface MessengerPerformanceReport {
  messengerId: string;
  messengerName: string;
  date: string;                          // "YYYY-MM-DD"
  totalDeliveries: number;
  averageDeliveryTimeMinutes: number;
  deliveries: MessengerDeliveryPerformance[];
}
listenRecentCompletedDeliveries(callback) — Real-time Firestore listener returning the 10 most recently completed deliveries across all couriers, ordered by deliveredAt descending. Elapsed time is calculated as deliveredAt - assignedAt (or createdAt as fallback) in minutes.getMessengers() returns active users with roles containing mensajero for the courier filter dropdown.
The CourierSessionsValidation component fetches from GET /api/admin/courier_sessions via getPendingClosures in sessionsService.ts. Sessions are sourced from the messenger_shift_closures Firestore collection.Query parameters:
ParameterDefaultDescription
status'closed'Filter by closure status (closed, validated, rejected)
limit20Page size (max 50)
cursorDocument ID of the last item for cursor-based pagination
Response shape:
{
  "closures": [
    {
      "id": "user-luis_2026-05-15",
      "courierId": "uid_abc",
      "courierName": "Luis Mamani",
      "dateKey": "2026-05-15",
      "status": "closed",
      "startedAt": "2026-05-15T08:00:00.000Z",
      "closedAt": "2026-05-15T18:30:00.000Z",
      "summary": {
        "completedCount": 12,
        "pendingCount": 1,
        "notDeliveredCount": 0,
        "cancelledCount": 0,
        "totalCollected": 480.00
      },
      "completedOrders": [],
      "pendingOrders": [],
      "incidentOrders": [],
      "validatedBy": null,
      "validatedByName": null,
      "validatedAt": null,
      "rejectionReason": null
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
To approve or reject a closure, PATCH /api/admin/courier_sessions is called with { closureId, action: "approve" | "reject", rejectionReason? }. A closure that has already been validated or rejected cannot be modified (returns 409).
The SellerActivityPanel subscribes to the sellerActivityLogs Firestore collection via getSellerActivityLogs in sellerActivityService.ts. Each document records a single action taken by a seller on an order.SellerActivityLog fields:
FieldTypeDescription
logIdstringFirestore document ID
sellerIdstringUID of the seller
sellerNamestringDisplay name at time of action
sellerEmailstringEmail at time of action
actionTypeSellerActionTypeOne of the action types below
orderIdstringAffected order ID
previousStatusstringOrder status before the action
newStatusstringOrder status after the action
timestampDateServer-side timestamp
SellerActionType values:
ValueLabel
RESERVARReservar
CANCELARCancelar
MARCAR_LISTOMarcar listo
ASIGNARAsignar mensajero
REASIGNARReasignar mensajero
MARCAR_PAGADAMarcar pagada
MARCAR_DEVUELTAMarcar devuelta
Filter support: by sellerId, actionType, and startDate/endDate. getSellersFromLogs() derives the unique seller list from existing log documents without querying the users collection.
The useOrdersList hook drives a paginated table of all orders via GET /api/admin/orders_list.Query parameters:
ParameterDefaultDescription
statusFilter by order status string
limit20Page size (max 50)
cursororderId of the last document for pagination
Response shape:
{
  "orders": [
    {
      "orderId": "uuid_FRIENDLYNAME",
      "customerName": "María García",
      "total": 45.50,
      "status": "ENTREGADO",
      "paymentStatus": "VERIFICADO",
      "deliveryStatus": "delivered",
      "createdAt": "2026-05-15T14:22:00.000Z",
      "cancelledAt": null,
      "incidentReason": null
    }
  ],
  "hasMore": true,
  "nextCursor": "uuid_NEXTORDER"
}
Buyer names are resolved server-side by batch-fetching users documents in parallel, so customerName is always the human-readable display name when available.

Build docs developers (and LLMs) love