aeat.adapters.outbound.aeat.export._formats._record_spec module

Fixed-width record-spec primitives for explicit fichero-BOE layouts.

The RecordFieldSpec and SegmentSpec records describe a small adapter-local fixed-width layout that can be passed to adapters.outbound.aeat.export._formats._serialise.serialise() or adapters.outbound.aeat.export._formats._deserialise.deserialise(). The canonical product export path is registry-backed: domain.calculations.registry.ExportLayoutDefinition and domain.calculations.registry.ExportRecordDefinition drive application.filing.export_draft() and domain.calculations.registry.parse_export_payload().

Primitive-safety contract:

Explicit-spec callers pin the concrete wire encoding via the FicheroBoeEncoding literal.

See also

domain.calculations.registry.ExportFieldDefinition

Canonical registry field declaration for modelo export layouts.

adapters.outbound.aeat.export.AeatExportFormatError

Error raised when an explicit fixed-width spec or encoded value violates the adapter contract.

FicheroBoeEncoding

Allowed wire encodings for fichero-BOE payloads.

Windows-1252 is a superset of ISO-8859-1 that adds characters in the 0x80-0x9F range; AEAT treats them as equivalent for fichero-BOE purposes. ISO-8859-15 adds the Euro symbol at 0xA4 plus other minor deltas needed by some annual informativas.

alias of Literal[‘cp1252’, ‘iso-8859-1’, ‘iso-8859-15’]

class FieldKind(*values)[source]

Bases: StrEnum

Semantic kind of a fixed-width field.

Determines the pad-character and justification defaults plus the encoder routing performed in adapters.outbound.aeat.export._formats._serialise.serialise().

Variables:
  • ALPHANUMERIC – Free-form text fields; left-justified, space-padded by default.

  • NUMERIC – Integer-shaped numeric fields; right-justified, zero-padded by default.

  • CURRENCY – Two-decimal monetary amounts encoded as zero-padded cents via encode_currency().

  • DATE – Calendar date encoded per the field’s DateFmt.

  • RESERVED – Literal constant slots, separators, envelope opener / closer) emitted verbatim from RecordFieldSpec.literal_value.

ALPHANUMERIC
NUMERIC
CURRENCY
DATE
RESERVED
class Justification(*values)[source]

Bases: StrEnum

Fixed-width field alignment.

Variables:
  • LEFT – Pad on the right.

  • RIGHT – Pad on the left.

LEFT
RIGHT
class DateFmt(*values)[source]

Bases: StrEnum

BOE date shapes encountered across fixed-width record designs.

The concrete registry spec pins the shape per field.

Variables:
  • YYYYMMDD – Year-first calendar date, eight ASCII digits.

  • DDMMYYYY – Day-first calendar date, eight ASCII digits.

YYYYMMDD
DDMMYYYY
class SignedMode(*values)[source]

Bases: StrEnum

Sign-convention for a CURRENCY field.

AEAT record designs can use different conventions for negative amounts in the fichero-BOE wire format. Registry-backed definitions declare the correct mode per field; the serialiser routes to encode_currency() accordingly.

Variables:
  • UNSIGNED – Field is always non-negative. Callers must either pass abs(value) or rely on an adjacent SIGNO / TIPO flag elsewhere in the record.

  • INLINE_SIGN – Byte 0 is "N" for negatives or " " for non-negatives; remaining bytes carry the absolute magnitude.

UNSIGNED
INLINE_SIGN
class RecordFieldSpec(**data)[source]

Bases: BaseModel

One fixed-width field in a fichero-BOE record.

Strict / frozen / extra="forbid" per the project’s boundary-record mandate. Validated when the concrete spec tuple is constructed via record_field() and validate_record_specs().

Variables:
  • offset – 1-based byte offset per BOE convention.

  • length – Field byte length.

  • field_id – AEAT field identifier. The 96-char cap accommodates descriptive names from official record designs.

  • casilla_id – Optional mapping to a registry casilla. None for header, reserved, or literal fields that do not correspond to a casilla.

  • kind – Semantic FieldKind selecting the encoder route.

  • justification – Where to align the value within the length window.

  • pad_char – Single-byte pad character (typically " " for text, "0" for numeric).

  • literal_value – For RESERVED literal fields, the exact byte string to emit. Required when kind == RESERVED and forbidden otherwise.

  • date_fmt – Required when kind == DATE; ignored otherwise.

  • signed_mode – How CURRENCY fields encode negative amounts. Defaults to UNSIGNED. Set to INLINE_SIGN for fields that carry the sign in the leading byte. Ignored for non-CURRENCY kinds.

Parameters:
  • offset (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=1)])])

  • length (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=1)])])

  • field_id (Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1), MaxLen(max_length=96)])])

  • casilla_id (CasillaId | None)

  • kind (FieldKind)

  • justification (Justification)

  • pad_char (Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1), MaxLen(max_length=1)])])

  • literal_value (str | None)

  • date_fmt (DateFmt | None)

  • signed_mode (SignedMode)

See also

domain.calculations.registry.ExportFieldDefinition

Registry-backed declaration used by the application export renderer.

record_field()

Compact constructor that applies kind-aware defaults before producing this record.

offset: Annotated[int, Field(ge=1)]

1-based byte offset per BOE convention.

length: Annotated[int, Field(ge=1)]

Field byte length.

field_id: Annotated[str, Field(min_length=1, max_length=96)]

AEAT field identifier.

casilla_id: CasillaId | None

Optional mapping to a canonical registry casilla.id.

kind: FieldKind
justification: Justification

Where to align the value within the length window.

pad_char: Annotated[str, Field(min_length=1, max_length=1)]

Single-byte pad character.

literal_value: str | None

the exact byte string to emit.

Type:

For RESERVED / literal fields

date_fmt: DateFmt | None

Required when kind == DATE; ignored otherwise.

signed_mode: SignedMode

How CURRENCY fields encode negative amounts.

record_field(*, offset, length, field_id, casilla_id=None, kind, justification=None, pad_char=None, literal_value=None, date_fmt=None, signed_mode=SignedMode.UNSIGNED)[source]

Concise constructor for RecordFieldSpec.

Mirrors the compact registry declaration style. Applies kind-appropriate defaults for justification and pad_char so most field declarations only need offset / length / field_id / kind:

  • NUMERIC and CURRENCY are right-justified and zero-padded.

  • ALPHANUMERIC, RESERVED, and DATE are left-justified and space-padded.

Parameters:
  • offset (int) – 1-based byte offset within the record.

  • length (int) – Field byte length.

  • field_id (str) – AEAT field identifier.

  • casilla_id (TypeAliasType | None) – Optional canonical registry casilla mapping.

  • kind (FieldKind) – Semantic FieldKind.

  • justification (Justification | None) – Override the kind-aware default justification.

  • pad_char (str | None) – Override the kind-aware default pad character.

  • literal_value (str | None) – Required for kind == RESERVED.

  • date_fmt (DateFmt | None) – Required for kind == DATE.

  • signed_mode (SignedMode) – Sign convention for kind == CURRENCY.

Return type:

RecordFieldSpec

Returns:

A validated RecordFieldSpec.

encode_currency(value, *, length, signed=False, inline_sign=False, encoding)[source]

Encode currency as right-justified, zero-padded cents with two implicit decimals.

AEAT fichero-BOE currency fields emit the value * 100 integer with no separators. Decimal("1234.56") in a length-13 field produces b"0000000123456".

Rounding uses an explicit decimal.ROUND_HALF_UP to match AEAT Instrucciones de cumplimentación — not banker’s rounding — so Decimal("2.005") rounds to b"000201".

Parameters:
  • value (Decimal) – Monetary amount to encode. Must be non-negative unless signed or inline_sign is True.

  • length (int) – Total field width in bytes (including the sign byte when inline_sign=True).

  • signed (bool) – When True, allow negative inputs whose sign has been wired through a separate SIGNO / TIPO field elsewhere in the record.

  • inline_sign (bool) – When True, switch to the leading "N" / " " sign-byte convention. The remaining length - 1 bytes carry the zero-padded absolute magnitude.

  • encoding (Literal['cp1252', 'iso-8859-1', 'iso-8859-15']) – Output byte encoding.

Return type:

bytes

Returns:

The fixed-width byte sequence for the currency field.

Raises:

AeatExportFormatError – If value is negative without signed or inline_sign, the magnitude overflows length, or inline_sign=True is used with length < 2.

encode_text(value, *, length, justification=Justification.LEFT, pad_char=' ', truncate=False, encoding)[source]

Encode an alphanumeric value into a fixed-width byte field.

Parameters:
  • value (str) – Text value to encode.

  • length (int) – Target field width in bytes.

  • justification (Justification) – Where to align value within length.

  • pad_char (str) – Single-character pad applied to fill the remainder.

  • truncate (bool) – When False (default), raise on overflow rather than silently clipping. A mis-measured spec that would clip an identity or name field is a legally-binding corruption — fail loud. Set truncate=True only when the caller has a concrete reason to allow clipping.

  • encoding (Literal['cp1252', 'iso-8859-1', 'iso-8859-15']) – Wire encoding supplied by the registry export layout.

Return type:

bytes

Returns:

The fixed-width byte sequence.

Raises:

AeatExportFormatError – If pad_char is not exactly one character or len(value) > length and truncate is False.

encode_date(value, fmt, *, encoding)[source]

Encode a datetime.date per the BOE Diseño de registros fmt.

Parameters:
  • value (date) – Calendar date to encode.

  • fmt (DateFmt) – Wire-format selector.

  • encoding (Literal['cp1252', 'iso-8859-1', 'iso-8859-15']) – Output byte encoding.

Return type:

bytes

Returns:

Eight-byte ASCII representation of the date.

class SegmentSpec(**data)[source]

Bases: BaseModel

A named, variable-length segment in a multi-segment fichero-BOE envelope.

Some AEAT record designs are not a single flat record. The on-wire format can be an envelope like:

<SEG0> ... </SEG0> ... <SEG1>page1</SEG1> ...

Each segment is itself a fixed-width record with its own field layout, opener + closer literal, and byte length. Segment IDs reset their internal offsets to 1.

A SegmentSpec carries one segment’s layout. The envelope itself is a tuple of SegmentSpec plus a selector that decides which optional segments are emitted.

Variables:
  • segment_id – AEAT segment identifier.

  • specs – The field layout for this segment. Offsets are segment-local (1-based within this segment, not global).

  • total_length – Byte content length of this segment, excluding any CRLF terminator.

Parameters:
  • segment_id (Annotated[str, FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1), MaxLen(max_length=32)])])

  • specs (tuple[RecordFieldSpec, ...])

  • total_length (Annotated[int, FieldInfo(annotation=NoneType, required=True, metadata=[Ge(ge=1)])])

See also

domain.calculations.registry.ExportRecordDefinition

Registry-backed record declaration for the active modelo export renderer.

adapters.outbound.aeat.export._formats._serialise.serialise_envelope()

Explicit-spec envelope serialiser that consumes segments.

segment_id: Annotated[str, Field(min_length=1, max_length=32)]
specs: tuple[RecordFieldSpec, ...]
total_length: Annotated[int, Field(ge=1)]
validate_segment_specs(segments)[source]

Enforce per-segment invariants at import time.

Runs validate_record_specs() on each segment and checks that segment IDs are unique across the envelope. Does NOT enforce a global offset — each segment resets to 1.

Parameters:

segments (tuple[SegmentSpec, ...]) – Ordered tuple of SegmentSpec to validate.

Raises:

AeatExportFormatError – If segments is empty, a segment_id repeats, or any segment fails its internal validate_record_specs() check.

Return type:

None

validate_record_specs(specs, *, total_length)[source]

Enforce the monotonic offset / length invariant for one segment.

Registry-backed loaders call this before a filing layout can be used to guard against off-by-one errors that would cascade through every subsequent field. The checks are:

  • First field starts at offset 1 (BOE 1-based convention).

  • Fields are monotonically contiguous: no gaps, no overlaps.

  • Terminal field fills exactly to total_length.

  • field_id values are unique.

  • casilla_id values are unique where non-None.

Parameters:
  • specs (tuple[RecordFieldSpec, ...]) – Ordered tuple of field specs covering the segment.

  • total_length (int) – Expected segment byte content length.

Raises:

AeatExportFormatError – Carries a precise pointer (field id, offset, expected vs actual) for any violation.

Return type:

None