Skip to content

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 File row 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