Skip to content

Data Model

This page is the canonical reference for which database columns are PAC-related, what they mean, and where they're written.

tenants

app/core/db/tenant_model.py

Column Type Purpose
pac_company_id String(255) Alanube's company ID for this tenant. Returned by POST /pan/v1/companies during onboarding. The webhook URL /webhooks/pac/{company_id} matches against this column.

If this is NULL, the tenant cannot issue PAC documents at all.

offices

app/graphql/companies/models.py

Column Type Purpose
pac_office_id String(50) Alanube's office ID. Returned by POST /pan/v1/companies/{id}/offices.
code String(4) 4-digit office code, e.g. 0001.
coordinates String(22) "+9.0017832,-79.5275519"
address String(100) Physical address.
telephone String(12) Phone for the office.
type String(20) "main" or "associated".
email String(50) Office contact email.
location String(255) DGI province/district/corregimiento code, e.g. 8-8-11.

A tenant must have at least one office before issuing invoices.

invoices

app/graphql/invoices/models/invoice.py

PAC-relevant columns:

Column Type Written by Meaning
invoice_number String(255) factory + PAC response The CUFE. Set after Alanube authorizes.
document_id String(255) PAC response Alanube's internal ID. Used for all subsequent GET/DELETE calls.
legal_status String(50) webhook / poller One of PAC_AUTHORIZED, DGI_AUTHORIZED, PAC_REJECTED, DGI_REJECTED.
pac_input JSONB InvoicePacService Full payload sent to PAC (audit / replay).
pac_response JSONB InvoicePacService Full response from PAC.
qr_code_url Text webhook / poller DGI QR code link.
invoice_generation_mode IntEnum mutation input PROFORM, DGI, or DGI_IMPORT.
office_id UUID FK mutation input Which office issued the invoice; maps to pac_office_id.
adhoc_client_name String(255) mutation input Override the registered client's name on the PAC payload.
adhoc_client_ruc String(255) mutation input Override the registered client's RUC.
emails_ad_hoc Array[String] mutation input Override receiver emails.

credits

app/graphql/credits/models/credit.py

Same shape as invoices, but the CUFE column is named credit_number:

Column Type Meaning
credit_number String(255) Credit note CUFE.
document_id String(255) Alanube's internal ID.
legal_status String(50) Same enum as invoices.
pac_input, pac_response JSONB Audit.
qr_code_url Text DGI QR.
credit_generation_mode IntEnum PROFORM, DGI, DGI_IMPORT.
office_id UUID FK Issuing office.

A credit also references the source invoice — see Credit Notes.

Migration history

The pac_input / pac_response columns were added in alembic/versions/20260215_add_pac_input_and_response_to_invoices_and_credits.py. Older invoices in the DB may have these as NULL; consumers must tolerate that.

Why both document_id and CUFE?

  • document_id exists from the moment Alanube acknowledges the submission, even if the document is later rejected. It's the lookup key for all PAC API calls.
  • CUFE only exists once the document is at least PAC-authorized. It's printed on the PDF and used by the receiver.

For lookups in our own code, always prefer document_id — it's stable and unique. Use CUFE only when matching webhook payloads that lack a document_id (rare).