Legal Status as a proper IntEnum¶
Date: 2026-06-03
Problem / motivation¶
legal_status on invoices and credits was a free-form String(50) column, and the
GraphQL surface exposed it as a plain String. Every other enumerated field in the codebase
(InvoiceStatus, InvoiceGenerationMode, PaymentTerms, CodigoRetencion, …) is a
@strawberry.enum-decorated enum.IntEnum stored via the IntEnum SQLAlchemy
TypeDecorator. Legal status was the odd one out: stringly-typed in the DB, in the ORM, in the
DTOs, and duplicated by a separate PacLegalStatus(str, Enum) used only for webhook parsing.
This makes the column a first-class LegalStatus IntEnum like everything else.
In scope¶
- New
LegalStatus(enum.IntEnum)(@strawberry.enum) inapp/graphql/common/models/legal_status.py. invoices.legal_statusandcredits.legal_statuscolumns becomeSmallIntegerviaIntEnum(LegalStatus).- All DTOs (
InvoiceLite,InvoiceLandingPage,Credit,CreditLandingPage) exposeLegalStatus. - All write sites convert the Alanube wire string →
LegalStatusviaLegalStatus.from_pac(...). - The redundant
PacLegalStatus(str, Enum)is removed; webhook models parse the wire string intoLegalStatus. - Admin PAC report filters take a
LegalStatusenum arg (serialized back to the Alanube wire name). - Two alembic migrations (one per table) convert the existing string data in place.
Out of scope¶
- No change to the Alanube wire protocol.
PacDocumentResponse.legal_statusstays astr(raw transport DTO). - No new legal-status values; the four Alanube terminal/intermediate states (
PAC_AUTHORIZED,PAC_REJECTED,DGI_AUTHORIZED,DGI_REJECTED) are the complete set perdocs/pac/.
Data model changes¶
20260603_convert_invoices_legal_status_to_int_enum.py—revision="legal_status_int_invoices",down_revision="rehash_ledger_audit_logs".ALTER COLUMN legal_status TYPE SMALLINT USING (CASE …).20260603_convert_credits_legal_status_to_int_enum.py—revision="legal_status_int_credits",down_revision="legal_status_int_invoices". Same shape oncredits.
Mapping (stable, hard-coded in the migrations and in the enum's explicit member values):
| wire string | int |
|---|---|
PAC_AUTHORIZED |
1 |
PAC_REJECTED |
2 |
DGI_AUTHORIZED |
3 |
DGI_REJECTED |
4 |
NULL |
NULL |
GraphQL surface¶
- Changed type —
Invoice.legalStatus,InvoiceLite.legalStatus,InvoiceLandingPage.legalStatus,Credit.legalStatus,CreditLandingPage.legalStatuschange fromStringto the newLegalStatusenum. - Admin —
pacDocumentsReport/pacDocumentsReportAllCompanieslegalStatusarg changes fromStringtoLegalStatus.
Frontend contract¶
Runtime JSON is unchanged: Strawberry serializes enum members by name, so clients still receive
the exact same strings ("PAC_AUTHORIZED", "DGI_AUTHORIZED", …) and null. The only difference is
the SDL now types the field as the LegalStatus enum instead of String. Clients that treat it as an
opaque string need no change; clients generating typed bindings should regenerate. Admin report filters
now require one of the enum members instead of an arbitrary string.
Open questions¶
None.