aeat.application.ledger._business_operation_invoice module

Payable and collectible invoice CRUD services.

Two noun-groups (payable_invoice, collectible_invoice) each expose the canonical five-verb CRUD spine add/remove/update/view/list. Records are bucket-scoped and persisted as encrypted BusinessOperationInvoiceDocument payloads through SecureBoundRepository per noun-kind, under the aeat.adapters.persistence.storage.LEDGER_BUSINESS_OPERATION_INVOICE_NAMESPACE namespace contract.

The records are intentionally slim. Business-detail enrichment (line items, IVA breakdown, reconciliation linkages) belongs to the aeat.domain.invoices richer Invoice aggregate consumed by modelo aggregation pipelines. The noun-group records here are the canonical operator-edit surface for the two source-kind variants covered.

Bucket events emitted per mutating verb via BucketEventHistoryRepository:

add -> payable_invoice.created / collectible_invoice.created update -> payable_invoice.updated / collectible_invoice.updated remove -> payable_invoice.removed / collectible_invoice.removed

Read verbs (view, list) emit no bucket event per the MutatingNounGroupContract.

class BusinessOperationInvoiceDirection(*values)[source]

Bases: StrEnum

The two invoice-direction variants this module covers.

The member string values (payable_invoice / collectible_invoice) are the load-bearing internal source-kind taxonomy per aeat-spanish-stem-naming and are preserved; only the enum TYPE name is the direction axis.

PAYABLE_INVOICE
COLLECTIBLE_INVOICE
exception BusinessOperationInvoiceInputError(message=None, *, context=None, suggestion=None, translated_message=None)[source]

Bases: AeatError

Raised when a CLI-supplied input violates the typed contract.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • suggestion (str | None)

  • translated_message (str | None)

Return type:

None

code: ClassVar[ErrorCode]
exception BusinessOperationInvoiceNotFoundError(message=None, *, context=None, suggestion=None, translated_message=None)[source]

Bases: AeatError

Raised when a CLI lookup targets a missing record.

Parameters:
  • message (str | None)

  • context (Mapping[str, object] | None)

  • suggestion (str | None)

  • translated_message (str | None)

Return type:

None

code: ClassVar[ErrorCode]
validate_eu_iva_id(raw)[source]

Normalise and validate an EU IVA-ID.

Strips whitespace and hyphens, uppercases, then checks the two-letter country prefix against the per-member-state pattern table.

Returns the normalised value on success. Raises BusinessOperationInvoiceInputError on format mismatch.

Return type:

str

Parameters:

raw (str)

class BusinessOperationInvoice(**data)[source]

Bases: BaseModel

One persisted payable- or collectible-invoice record.

The source_kind discriminator binds the record to one of the two locked source-kind taxonomy values. invoice_id is the noun-group’s full_id; mutating verbs accept either invoice_id or any unambiguous prefix for partial-id matching.

Intracom fields (country_code, eu_iva_id, operation_type) are None for domestic invoices and are set for EU intracomunitaria operations that feed M349 aggregation. The current persisted shape always carries the three keys; domestic invoices record them explicitly as None.

Parameters:
invoice_id: str
source_kind: BusinessOperationInvoiceDirection
bucket_id: BucketId
counterparty_nif: str
counterparty_name: str
invoice_number: str
invoice_date: str
currency: str
taxable_base: Decimal
iva_rate: Decimal | None
iva_amount: Decimal
total_amount: Decimal
notes: str
country_code: str | None
eu_iva_id: str | None
operation_type: IntracomOperationType | None
created_at: datetime
updated_at: datetime
derive_business_operation_invoice_id(*, bucket_id, source_kind, counterparty_nif, counterparty_name, invoice_number, invoice_date, currency, taxable_base, iva_rate, iva_amount, total_amount, notes, country_code, eu_iva_id, operation_type, created_at, disambiguator=0)[source]

Return the content-addressed id for a business-operation invoice record.

Mirrors aeat.domain.transactions.derive_transaction_id(): a SHA-256 digest (truncated to 16 hex chars, the prior surrogate’s width) over the record’s identifying fields, so the id is stable under a frozen-clock replay and directly referenceable as an aeat app ledger invoice argument, needing no output mask. created_at plus the disambiguator ordinal preserve the genuine-duplicate case: two legitimately distinct invoices must keep distinct ids, so the mint site increments disambiguator on the rare digest collision rather than colliding.

Return type:

str

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

Bases: BaseModel

Partial update payload for an existing record.

Every field is optional; only provided fields overwrite the existing record. invoice_id, source_kind, and bucket_id are immutable and cannot be patched.

Parameters:
  • counterparty_nif (str | None)

  • counterparty_name (str | None)

  • invoice_number (str | None)

  • invoice_date (str | None)

  • currency (str | None)

  • taxable_base (Decimal | None)

  • iva_rate (Decimal | None)

  • iva_amount (Decimal | None)

  • total_amount (Decimal | None)

  • notes (str | None)

  • country_code (str | None)

  • eu_iva_id (str | None)

  • operation_type (IntracomOperationType | None)

counterparty_nif: str | None
counterparty_name: str | None
invoice_number: str | None
invoice_date: str | None
currency: str | None
taxable_base: Decimal | None
iva_rate: Decimal | None
iva_amount: Decimal | None
total_amount: Decimal | None
notes: str | None
country_code: str | None
eu_iva_id: str | None
operation_type: IntracomOperationType | None
class BusinessOperationInvoiceResult(**data)[source]

Bases: BaseModel

Return record from a mutating invoice verb — record plus emitted event id.

Parameters:
record: BusinessOperationInvoice
bucket_event_ids: tuple[str, ...]
class BusinessOperationInvoiceDocument(**data)[source]

Bases: BaseModel

Encrypted bucket-local business-operation invoice catalogue.

Parameters:
bucket_id: BucketId
source_kind: BusinessOperationInvoiceDirection
records: tuple[BusinessOperationInvoice, ...]
class BusinessOperationInvoiceRepository(*, bucket_id=None, objects=None, settings=None)[source]

Bases: SecureBoundRepository[BusinessOperationInvoiceDocument]

Encrypted store for one bucket/source-kind invoice catalogue.

The namespace, sensitivity, schema version, and object-key contract come from aeat.adapters.persistence.storage.LEDGER_BUSINESS_OPERATION_INVOICE_NAMESPACE. The SecureBoundRepository base wraps each BusinessOperationInvoiceDocument in a Envelope before writing it.

See also

BusinessOperationInvoiceDocument

Bucket-local payload grouped by invoice direction.

PayableInvoiceService

CRUD service for vendor invoices.

CollectibleInvoiceService

CRUD service for customer invoices.

Parameters:
namespace: ClassVar[str]
sensitivity: ClassVar[SensitivityClass]
schema_version: ClassVar[int]
payload_type

alias of BusinessOperationInvoiceDocument

extract_identifier(payload)[source]

Return the natural id for payload (used as the SQL object key).

Subclasses MUST override. The base implementation raises NotImplementedError.

Return type:

str

Parameters:

payload (BusinessOperationInvoiceDocument)

class PayableInvoiceService(settings=None, bucket_event_repository=None)[source]

Bases: _BusinessOperationInvoiceService

CRUD service for payable_invoice records (we owe vendor).

Parameters:
source_kind: BusinessOperationInvoiceDirection
class CollectibleInvoiceService(settings=None, bucket_event_repository=None)[source]

Bases: _BusinessOperationInvoiceService

CRUD service for collectible_invoice records (customer owes us).

Parameters:
source_kind: BusinessOperationInvoiceDirection