Skip to main content

Sales Ledger Summary

Billing → Reports (/billing/BillingReportsPage) includes the Sales Ledger Summary dashboard (code sales-ledger-summary). It is allowed for the roles owner, admin, and accountant.

The dashboard answers two questions, in that order on the page:

  1. Daily — certified sales by location and issue date, with annulled documents beside that day's certified total.
  2. Period — the same documents rolled into goods, services, exempt, IVA, and a period total.

Voided and cancelled amounts are their own rows. They do not change Monto total or Total del período.

Where the numbers come from​

Classification is the SQL function fel_sales_ledger_document(business_id, start_date, end_date). The Metabase cards only aggregate it:

CardFile
Dailyscripts/metabase/card-definitions/flowpos-sales-sales-ledger-summary-daily.sql
Periodscripts/metabase/card-definitions/flowpos-sales-sales-ledger-summary-period.sql

Both cards take business_id, start_date, and end_date. They do not read sale or order_bill themselves.

Sales Book (flowpos-sales-sales-book) is a sibling report. It keeps its own SQL. Pointing Sales Book at fel_sales_ledger_document would change that book; this dashboard does not do that.

The layout script writes numeric Metabase ids onto the dashboard row. It does not contain the classification. Re-running it is safe:

SSL_DISABLE=true tsx src/metabase/layout-sales-ledger-summary.ts --env local
SSL_DISABLE=true tsx src/metabase/layout-sales-ledger-summary.ts --env staging
SSL_DISABLE=true tsx src/metabase/layout-sales-ledger-summary.ts --env production --yes

Run it from packages/backend/scripts. The dashboard row must already exist. A missing Billing Reports form (path /billing/BillingReportsPage) fails the schema change that registers the dashboard.

What counts as a document​

Each returned row has kind, location_name, emission_date, goods, services, exempt, iva_goods, iva_services, document_total, and annulled_amount. A blank location name is stored as Sin ubicación. The location timezone defaults to America/Guatemala.

The window is location-local calendar days: from the start of start_date's local day through the end of end_date (exclusive of the next midnight).

Certified retail (kind = certified)​

A sale row (a null type counts as sale) with fel_status = certified, a non-empty fel_authorization, and a status outside draft, cancelled, voided, and pending_approval.

Issue date is fel_date_dte when it parses, otherwise sale_date. Accepted fel_date_dte shapes are an ISO prefix (YYYY-MM-DD…) and DD/MM/YYYY HH24:MI.

Line split, from sale_detail.items:

BucketRule
GoodsitemType is not service, and the line's IVA is greater than 0. Amount is taxableAmount
ServicesitemType is service, and IVA is greater than 0. Amount is taxableAmount
ExemptIVA is 0. Goods and services are added together. Amount is amount
IVASum of tax lines whose shortCode, code, or shortName is IVA. A non-empty taxes array with no IVA line contributes 0. A missing taxes array falls back to the line taxAmount

document_total is the header total_amount. It is not recomputed from the buckets, so a header that disagrees with its lines still shows the header as Monto total. annulled_amount is 0 on certified rows.

Credit notes and other non-sale types are absent.

Certified restaurant (kind = certified)​

An order_bill with fel_status = certified, a non-empty fel_authorization, and a status other than cancelled. Issue date is fel_date_dte, otherwise created_at. document_total is order_bill.total.

Taxed vs exempt follows item weight (unit_price_snapshot * split_quantity). Tips are added to exempt. Every restaurant line is classified as goods: is_service is fixed false, so the services bucket and services IVA are 0 for bills.

Annulled​

SourcekindAmount
Retail sale with status voided or cancelled (type sale, null counts as sale)the status stringtotal_amount in annulled_amount
Restaurant bill with status cancelledcancelledtotal in annulled_amount

These rows do not require a certified DTE. Goods, services, exempt, IVA, and document_total are 0. A cancelled sale that never received an authorization still appears here when its status is cancelled or voided.

How the cards present it​

Daily groups by location and issue date. Certified columns (registros, bienes, servicios, exentas, IVA, monto total) count kind = certified only. Registros anulados and Monto anulado count voided and cancelled. Each location ends with a Total row.

Period emits five concepts per location, in this order:

ConceptoValor netoIVA débitoValor total
Venta de bienescertified goodscertified IVA on goodsgoods + that IVA
Prestación de servicioscertified servicescertified IVA on servicesservices + that IVA
Ventas exentascertified exempt0exempt
Ventas anuladas o canceladasannulled amountemptyempty
Total del períodogoods + services + exemptboth IVA columnssum of certified document_total

Total del período valor total is the sum of certified headers. It is not goods + services + exempt + IVA, and it does not subtract annulled amounts.