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:
encode_currency()uses explicitdecimal.ROUND_HALF_UPmatching the AEAT Instrucciones de cumplimentación (not banker’s rounding).encode_text()raises on overflow (no silent truncation) to prevent identity or name-field corruption from mis-measured specs.RecordFieldSpecenforces the RESERVED ↔literal_valueinvariant at construction time.validate_record_specs()enforces monotonicoffset + length == next.offsetacross a spec tuple.
Explicit-spec callers pin the concrete wire encoding via the
FicheroBoeEncoding literal.
See also
domain.calculations.registry.ExportFieldDefinitionCanonical registry field declaration for modelo export layouts.
adapters.outbound.aeat.export.AeatExportFormatErrorError 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:
StrEnumSemantic 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:
StrEnumFixed-width field alignment.
- Variables:
LEFT – Pad on the right.
RIGHT – Pad on the left.
- LEFT¶
- RIGHT¶
- class DateFmt(*values)[source]¶
Bases:
StrEnumBOE 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:
StrEnumSign-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:
BaseModelOne 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 viarecord_field()andvalidate_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.
Nonefor header, reserved, or literal fields that do not correspond to a casilla.kind – Semantic
FieldKindselecting the encoder route.justification – Where to align the value within the
lengthwindow.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 == RESERVEDand forbidden otherwise.date_fmt – Required when
kind == DATE; ignored otherwise.signed_mode – How CURRENCY fields encode negative amounts. Defaults to
UNSIGNED. Set toINLINE_SIGNfor 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.ExportFieldDefinitionRegistry-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
lengthwindow.
- 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
justificationandpad_charso most field declarations only needoffset/length/field_id/kind:NUMERICandCURRENCYare right-justified and zero-padded.ALPHANUMERIC,RESERVED, andDATEare 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.justification (
Justification|None) – Override the kind-aware default justification.pad_char (
str|None) – Override the kind-aware default pad character.signed_mode (
SignedMode) – Sign convention forkind == CURRENCY.
- Return type:
- 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 * 100integer with no separators.Decimal("1234.56")in a length-13 field producesb"0000000123456".Rounding uses an explicit
decimal.ROUND_HALF_UPto match AEAT Instrucciones de cumplimentación — not banker’s rounding — soDecimal("2.005")rounds tob"000201".- Parameters:
value (
Decimal) – Monetary amount to encode. Must be non-negative unlesssignedorinline_signisTrue.length (
int) – Total field width in bytes (including the sign byte wheninline_sign=True).signed (
bool) – WhenTrue, allow negative inputs whose sign has been wired through a separate SIGNO / TIPO field elsewhere in the record.inline_sign (
bool) – WhenTrue, switch to the leading"N"/" "sign-byte convention. The remaininglength - 1bytes carry the zero-padded absolute magnitude.encoding (
Literal['cp1252','iso-8859-1','iso-8859-15']) – Output byte encoding.
- Return type:
- Returns:
The fixed-width byte sequence for the currency field.
- Raises:
AeatExportFormatError – If
valueis negative withoutsignedorinline_sign, the magnitude overflowslength, orinline_sign=Trueis used withlength < 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 alignvaluewithinlength.pad_char (
str) – Single-character pad applied to fill the remainder.truncate (
bool) – WhenFalse(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. Settruncate=Trueonly 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:
- Returns:
The fixed-width byte sequence.
- Raises:
AeatExportFormatError – If
pad_charis not exactly one character orlen(value) > lengthandtruncateisFalse.
- encode_date(value, fmt, *, encoding)[source]¶
Encode a
datetime.dateper the BOE Diseño de registrosfmt.
- class SegmentSpec(**data)[source]¶
Bases:
BaseModelA 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
SegmentSpeccarries one segment’s layout. The envelope itself is a tuple ofSegmentSpecplus 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:
See also
domain.calculations.registry.ExportRecordDefinitionRegistry-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 ofSegmentSpecto validate.- Raises:
AeatExportFormatError – If
segmentsis empty, asegment_idrepeats, or any segment fails its internalvalidate_record_specs()check.- Return type:
- 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_idvalues are unique.casilla_idvalues 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: