cadrumo.application.invoices.catalogue_lifecycle module

Application lifecycle services for the rich catalogue Invoice.

Reads and mutates the InvoiceCatalogue aggregate.

The reconciliation catalogue gained create and list operator verbs but no way to inspect or delete a single record. Without a single-record read an operator cannot confirm the long content-addressed invoice_id that aeat app ledger link --invoice-id resolves, nor see which transactions a catalogue invoice already binds; without a delete a mistaken catalogue create is permanent. These two services close that CRUD gap over the same application-owned catalogue lifecycle capabilities. These verbs are the operator’s single-record surface over the canonical aggregate; an earlier form of this docstring justified them as “keeping the slim-vs-rich split intact”, which is a rationale the canonical-structure work removes – the split is being retired, and these verbs survive it as the surviving store’s own CRUD.

resolve_catalogue_invoice() resolves a full id or an unambiguous prefix to one Invoice. remove_catalogue_invoice() deletes one record, refusing an invoice that still carries linked_transaction_ids so the bidirectional link recorded on the transaction side is never silently orphaned into a one-sided inconsistency (verify_link_consistency).

class CatalogueInvoiceRemoveResult(**data)[source]

Bases: BaseModel

Result of deleting one rich catalogue invoice.

Parameters:

data (Any)

invoice: Invoice
catalogue: InvoiceCatalogue
resolve_catalogue_invoice(catalogue, invoice_id)[source]

Return one InvoiceCatalogue invoice by full id or unambiguous prefix.

A catalogue invoice carries a long content-addressed id; operators rarely type it in full. An exact match wins outright. Otherwise a case-sensitive prefix is accepted only when it is unambiguous: a prefix that matches more than one invoice is refused with the candidate set named, never silently resolved to the first hit.

Raises:
Return type:

Invoice

Returns:

The resolved Invoice.

Parameters:
resolve_catalogue_invoice_from_repository(*, invoice_id, ports)[source]

Load the catalogue and resolve one invoice by id or unambiguous prefix.

Return type:

Invoice

Returns:

The resolved Invoice.

Parameters:
remove_catalogue_invoice(*, bucket_id, invoice_id, ports)[source]

Delete one rich catalogue invoice and return the updated catalogue.

The id is resolved by full match or unambiguous prefix. An invoice that still carries linked_transaction_ids is refused: deleting it from the catalogue alone would leave the transaction side citing a vanished invoice — a one-sided link verify_link_consistency flags. The operator must unlink first. The write rides the required application-owned mutation capability; no parallel write path is introduced.

Return type:

CatalogueInvoiceRemoveResult

Parameters:
class CatalogueInvoicePatch(**data)[source]

Bases: BaseModel

The fields of a persisted canonical invoice an operator may correct.

Deliberately EXCLUDES every field the invoice id is derived from – kind, invoice number, issue date, counterparty tax id, currency and the totals. That exclusion is structural rather than a runtime refusal: a patch cannot even express an identity change, so there is no path where one is attempted and silently produces a record under a different id.

The reason is that the canonical id is CONTENT-ADDRESSED. Changing any of those fields does not correct the record, it describes a different invoice, and rewriting it in place would leave every transaction already linked to the old id pointing at something that no longer exists. The slim store this replaces had no such constraint because its id was independent of content; this is the narrowing that content-addressing buys, and it is stated in the update verb’s refusal rather than left for an operator to discover.

An operator who genuinely must change an identity field removes the record and creates it again – which the remove verb already guards, refusing to delete an invoice that still carries links.

Parameters:

data (Any)

counterparty_name: str | None
counterparty_country: str | None
notes: str | None
payment_status: PaymentStatus | None
iva_category: IvaCategory | None
operation_type: IntracomOperationType | None
operation_date: date | None
retention_rate: Decimal | None
retention_amount: Decimal | None
series: str | None
invoice_class: InvoiceClass | None
rectifies_invoice_number: str | None
payment_id: str | None
class CatalogueInvoiceUpdateResult(**data)[source]

Bases: BaseModel

Result of correcting one rich catalogue invoice.

Parameters:

data (Any)

invoice: Invoice
catalogue: InvoiceCatalogue
bucket_event_ids: tuple[str, ...]
update_catalogue_invoice(*, bucket_id, invoice_id, patch, ports, occurred_at=None, actor='cli')[source]

Apply a correction to one persisted canonical invoice.

Only fields present on the patch are changed; an omitted field keeps its stored value, so a correction never has to restate the whole record. The identity fields are absent from the patch model entirely, so the record’s invoice_id is stable across an update by construction and every transaction already linked to it stays bound.

linked_transaction_ids is carried forward explicitly rather than being left to survive by accident: it is the reason this aggregate is the reconciliation authority, and an update that dropped it would sever the bidirectional link without the operator asking for it.

The corrected record is re-validated in full, so a patch that would break an invariant – a retención above its base, a counterparty country that no longer matches the tax id – refuses rather than persisting an inconsistent invoice. The write rides the required application-owned mutation capability; no parallel write path is introduced.

Parameters:
  • bucket_id (str) – Profile bucket whose encrypted catalogue holds the record.

  • invoice_id (str) – Full id or an unambiguous prefix of the invoice to correct.

  • patch (CatalogueInvoicePatch) – The fields to change; omitted fields are left as stored.

  • ports (CatalogueLifecyclePorts) – Required read, mutation, and bucket-event capabilities.

  • occurred_at (datetime | None) – Event timestamp; defaults to now.

  • actor (str) – Who performed the correction, recorded on the event.

Return type:

CatalogueInvoiceUpdateResult

Returns:

The corrected invoice, the updated catalogue, and the emitted event id.

Raises: