Skip to content

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) in app/graphql/common/models/legal_status.py.
  • invoices.legal_status and credits.legal_status columns become SmallInteger via IntEnum(LegalStatus).
  • All DTOs (InvoiceLite, InvoiceLandingPage, Credit, CreditLandingPage) expose LegalStatus.
  • All write sites convert the Alanube wire string → LegalStatus via LegalStatus.from_pac(...).
  • The redundant PacLegalStatus(str, Enum) is removed; webhook models parse the wire string into LegalStatus.
  • Admin PAC report filters take a LegalStatus enum 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_status stays a str (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 per docs/pac/.

Data model changes

  • 20260603_convert_invoices_legal_status_to_int_enum.pyrevision="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.pyrevision="legal_status_int_credits", down_revision="legal_status_int_invoices". Same shape on credits.

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 typeInvoice.legalStatus, InvoiceLite.legalStatus, InvoiceLandingPage.legalStatus, Credit.legalStatus, CreditLandingPage.legalStatus change from String to the new LegalStatus enum.
  • AdminpacDocumentsReport / pacDocumentsReportAllCompanies legalStatus arg changes from String to LegalStatus.

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.