Restaurant FEL Workflow
This diagram shows the complete flow from restaurant order creation through FEL invoice certification. The buyer's NIT is captured at payment time and all six FEL columns are persisted inline after certification.
Prerequisites
| Configuration step | Where |
|---|---|
Business has FEL certifier config (felCertifierConfig on business) | Business settings |
At least one payment method has a documentPaymentMethod row with documentType = ORDER_BILL and generateElectronicTaxDocument = true | Payment method config |
Products have unitOfMeasure and type (goods vs. service) set | Product catalog |
Unit conventions
| Field | Units |
|---|---|
order_item.unit_price_snapshot | Minor (integer cents) |
order_item.tax_amount_snapshot | Major (decimal, e.g. 1.07) |
order_item.bundle_detail.unitPriceFinal | Major |
order_item.discount_detail.unitPriceFinal | Minor |
order_item_modifier.total_price_adjustment | Minor |
order_bill.total | Minor |
Flow
flowchart TD
A([Waiter creates order\nPOST /restaurant/orders]) --> B[Add order items\nPOST /restaurant/orders/:id/items]
B --> C[Create bill\nPOST /restaurant/order-bills\nbillNumber assigned]
C --> D[PWA: Record Payment dialog opens\nBillsSection.tsx]
D --> E[Cashier enters NIT\nvalidateNit — mod-11 check\nempty/CF allowed]
E -- invalid NIT --> E2[Inline error shown\nsubmit blocked]
E -- valid NIT --> F
F[Cashier selects payment method\nFEL badge shown if\ngenerateElectronicTaxDocument=true]
F --> G[POST /restaurant/order-bills/:billId/payments\namount, paymentMethodId,\ntaxId?, taxName?, taxAddress?, taxpayerType?]
G --> H{Is this the final\npayment that pays\nthe bill in full?}
H -- partial payment --> I[Payment recorded\nbill stays PENDING]
I --> F
H -- final payment --> J[DB transaction begins]
J --> K{Buyer tax fields\npresent in payload?}
K -- yes --> L[UPDATE order SET\ntaxId, taxName,\ntaxAddress, taxpayerType]
K -- no --> M
L --> M[INSERT orderBillPayment\nbill status → PAID\ntransaction commits]
M --> N[certifyPaidBillIfRequired called]
N --> O{Business has\nfelCertifierConfig?}
O -- no --> Z([Skip FEL\nnot configured])
O -- yes --> P
P[Load payment method IDs used on bill] --> Q{Any paymentMethodId has\ndocumentPaymentMethod row\nfor ORDER_BILL with\ngenerateElectronicTaxDocument=true?}
Q -- no --> Z
Q -- yes --> R
R[Load active order items\nvoidedAt=null, compedAt=null\nfrom orderBillMapping scope]
R --> S[Load products with\nname, unitOfMeasure, type, taxes]
S --> T[Load OrderItemModifiers\nbatch for all item IDs]
T --> U[Build receiver\norder.taxId ?? 'CF'\norder.taxName ?? 'CONSUMIDOR FINAL'\norder.taxAddress ?? 'CIUDAD'\norder.taxpayerType ?? 'NIT']
U --> V[toFelInvoiceItemInputFromOrderItem\nfor each active item\nfold modifiers into unitPrice\nprefer taxBreakdownSnapshot\nfallback: taxAmountSnapshot + IVA rebuild]
V --> W[buildFelInvoiceItems\nshared pure function\ntax rows, discount lines\nbundle handling, rounding]
W --> X[FelService.certifyDocument\nSerie, Numero, Autorizacion\nFecha_DTE, felCertificationDate\nfelAcknowledgmentOfReceipt]
X -- success --> Y[UPDATE order_bill SET\nfel_authorization\nfel_serial_number\nfel_number\nfel_date_dte\nfel_certification_date\nfel_acknowledgment_of_receipt\nis_exported_to_fel=true\nfel_uuid]
X -- certifier error --> Y2[try/catch swallowed\nSentry log\nbill stays PAID\nFEL columns stay null]
Y --> AA[PWA refetches bill]
Y2 --> AA
AA --> AB{bill.felExpected=true\nAND\nbill.isExportedToFel=false?}
AB -- yes --> AC[Warning toast\n'FEL invoice was not generated']
AB -- no --> AD([Done])
AC --> AD
AD --> AE{Print FEL invoice?}
AE -- yes --> AF[POST /document-print-jobs\ndocumentType=FEL_INVOICE\nsourceKind=orderBill\nsourceId=billId]
AF --> AG[buildFelInvoicePayloadFromOrderBill\nloads bill + order + business\n+ location + items via orderBillMapping\n+ payments via orderBillPayment]
AG --> AH([FEL invoice printed])
felExpected derivation
felExpected is a derived boolean returned on every bill response. The PWA uses it to distinguish:
felExpected=true+isExportedToFel=true→ certified successfully (normal)felExpected=true+isExportedToFel=false→ FEL was expected but failed (show warning)felExpected=false→ this bill is not subject to FEL (no warning)
It is computed by OrderBillService.mapBillToView without exposing shouldGenerateFelForBill as a public API.
Strict gating
FEL is skipped unless all of the following are true:
- Business
felCertifierConfigis set - At least one payment method used on the bill has an explicit
documentPaymentMethodrow withdocumentType = ORDER_BILLandgenerateElectronicTaxDocument = true
There is no "no rows → default true" fallback. Merchants must explicitly configure payment methods during onboarding.