Overview¶
The cast of characters¶
flowchart LR
Tenant[Tenant
Cifras user]
Cifras[Cifras Backend
this repo]
Alanube[Alanube PAC
certified intermediary]
DGI[DGI
Panama tax authority]
Receiver[Invoice receiver
customer / gov]
Tenant -->|GraphQL| Cifras
Cifras -->|REST
JSON + Bearer| Alanube
Alanube -->|XML signed| DGI
DGI -->|Authorization| Alanube
Alanube -->|Webhook| Cifras
Cifras -->|Email + PDF| Receiver
| Actor | Role |
|---|---|
| Tenant | A Cifras customer (a Panamanian business) issuing invoices. |
| Cifras backend | This codebase. Owns business logic, orchestrates PAC, persists state. |
| Alanube PAC | External certified provider. We call their REST API and receive their webhooks. |
| DGI | Panama's tax authority. Final source of truth on whether a document is legally valid. |
| Receiver | The customer that the invoice is issued to. Could be an individual, a business, or a government entity. |
Why a PAC is required¶
In Panama, an invoice is not legally valid until it carries a CUFE (Código Único de Factura Electrónica) issued through the DGI's electronic invoicing regime. The DGI does not accept submissions directly from arbitrary systems; submissions must come from a certified PAC. Alanube is one such PAC.
Cifras therefore never talks to the DGI directly. Every fiscal document that needs to be legalized goes through Alanube.
What documents go through PAC?¶
| Document | Code | Implementation status |
|---|---|---|
| Invoice (Factura) | 01 |
✅ Fully implemented |
| Credit Note (Nota de Crédito) | 02 |
✅ Fully implemented |
| Debit Note (Nota de Débito) | 03 |
🟡 Enum defined, no submission flow |
| Event | 04 |
🟡 Enum defined, no submission flow |
See PacDocumentType for the enum.
Generation modes¶
An invoice or credit can be generated in one of three modes (InvoiceGenerationMode / CreditGenerationMode):
| Mode | Behavior |
|---|---|
PROFORM |
Internal-only document. Never sent to PAC. No CUFE, no PDF from Alanube. |
DGI |
Standard path. Submitted to PAC → DGI for full authorization. |
DGI_IMPORT |
An externally-issued invoice imported into Cifras. Treated as a DGI document. |
Only DGI and DGI_IMPORT interact with PAC.
What "fiscally valid" looks like in our DB¶
A fully-authorized invoice has all of these set:
document_id— Alanube's internal ID for the document.invoice_number— the CUFE.legal_status = 'DGI_AUTHORIZED'.qr_code_url— link to the DGI QR code.pac_input/pac_response— full request/response JSON for audit.- A
Filerow attached with the signed PDF.
Anything less than that is either in-flight, rejected, or a proforma.
Where the code lives¶
| Layer | Path |
|---|---|
| Low-level Alanube client | app/wrappers/pac/ |
| Domain services | app/graphql/{invoices,credits,common}/services/ |
| GraphQL mutations / queries | app/graphql/{invoices,credits,common}/mutations/ |
| Webhook receiver | app/webhooks/ |
| Polling fallback | app/graphql/invoices/tasks/pac_status_poll_task.py |
| Admin / onboarding | app/admin/, onboard_tenant.py |