Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt

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

Order submission is triggered from the payment flow when the balance due reaches zero and the user taps Done.

Architecture

ComponentPathPurpose
useOrderSubmission hooksrc/features/sales/hooks/useOrderSubmission.tsManages submission state, handles session errors, generates posReference
API clientsrc/api/orders/client.tsTyped wrapper around postJson, injects CSRF token
ID generatorsrc/domain/orders/posReference.tsGenerates unique posReference
Backend linkagesrc/domain/orders/models.ts + usePOSStores posReference, odooOrderId, lineIdMap on each order

posReference format

NU/CFG{configId}/S{sessionId}/{timestamp}-{random}
Example: NU/CFG1/S42/1709123456789-3f7a The posReference is generated once and persisted before submission. Retries use the same reference for idempotency — Odoo returns the existing order if the reference is already known.

Submission flow

When hub sync is active, orders are finalized through the hub first. The hub calls hub_finalize_snapshot on Odoo, which runs the full fiscal pipeline (create_from_ui) inside a database savepoint. If the hub path fails for any reason, the frontend falls back to the direct API automatically.
1

Validate

Check that bootstrapState has valid config_id and session_id.
2

Choose path

If hub sync is active (transport.mode === "hub") → Hub finalization via transport.finalizeOrder(). Otherwise → Direct API (/orders/create or /orders/update).
3

Map payload

  • product_id strings → integers
  • tax_ids strings → integers
  • Payment lines include statementId, journalId, accountId, amount, and name (payment method name)
  • amountPaid (tendered) + amountReturn (cash change)
4

Submit

Hub path: Sends a full OrderSnapshot (lines, totals, payment lines) to the hub, which forwards to Odoo’s hub_finalize_snapshot. On failure, falls back to the direct API automatically.Direct path: POST to /orders/create or /orders/update.
5

Handle result

  • Success: local order marked paid, table freed, redirected to floor plan
  • no_pos_session: triggers global session guard (redirects/locks)
  • Other error: payment screen stays open, user can retry

Hub finalization backend

The hub_finalize_snapshot method on pos.order wraps create_from_ui in a database savepoint. If any part of order creation fails (e.g., payment processing), the entire operation rolls back atomically — no phantom draft orders are left behind. Key behaviors:
  • Default partner: When no customer is selected, config.default_partner_id is used (typically “CLIENTE DE CONSUMO 1”), ensuring the receivable account is available for payment processing.
  • Idempotency: If an order with the same pos_reference already exists and is paid, the existing order is returned.
  • Payment verification: After create_from_ui, the method verifies that statement_ids were actually created. If not, the savepoint rolls back.
  • Fiscal pipeline: The full NCF/DGII fiscal pipeline runs inside create_from_ui, so hub-finalized orders get the same fiscal treatment as direct API orders.

Payment mapping

Cash tenders    → first cash statement in session
Non-cash tenders → first non-cash statement in session
Cash overpay    → amount_return field; tendered cash amount stays in statement_ids

Usage

import { useOrderSubmission } from "@/features/sales/hooks/useOrderSubmission";

function PaymentScreen() {
  const { submitOrder, isSubmitting, error } = useOrderSubmission();
  const { state } = usePOS();

  const handlePay = async () => {
    const response = await submitOrder(state.activeOrder);
    // response.order_id contains the Odoo order ID
  };
}

Backend mode

The mode field on the request defaults to order when omitted. Other values: return (refund) and payment (invoice collection). See src/api/orders/types.ts for full request/response type definitions.