cadrumo.application.ledger.ratios module¶
Operator-facing extensions for the aeat app ledger ratios verb-group.
The existing usage-ratio CRUD verbs (list/set/unset) live in
the application-layer ledger actions backed by the domain
usage_ratios module. This module adds two read-only verbs that
close the discoverability and pre-calculate readiness gaps:
eligibleenumerate categories that may carry a user ratio,annotated with their statutory default ratio
validateinspect the persisted profile against eligibility andbound rules; report missing categories per modelo
- class EligibleCategoryRow(**data)[source]¶
Bases:
BaseModelOne row in the
ratios eligiblelisting.default_ratiois None for eligible categories whose proportionality rule does not ship a statutory default; the operator must supply an override before the modelo pre-calculate readiness check passes.- Parameters:
data (Any)
- category: SpendingCategory¶
- proportionality_kind: ProportionalityKind¶
- default_ratio: Decimal | None¶
- override_present: bool¶
- class RatiosValidationFinding(**data)[source]¶
Bases:
BaseModelOne issue raised by
ratios validatefor an eligible category.- Parameters:
data (Any)
- category: SpendingCategory¶
- kind: str¶
- detail: _FindingDetail¶
- class RatiosValidationReport(**data)[source]¶
Bases:
BaseModelResult of
ratios validate. Read-only, emits no bucket event.- Parameters:
data (Any)
- bucket_id: BucketId¶
- profile_present: bool¶
- eligible_count: NonNegativeInt¶
- overrides_count: NonNegativeInt¶
- missing_overrides: tuple[SpendingCategory, ...]¶
- findings: tuple[RatiosValidationFinding, ...]¶
- eligible_ratio_categories(profile, *, year, operation)[source]¶
Return all eligible categories with their default ratio + override flag.
The output is sorted by canonical category value so callers can diff snapshots without ordering noise. Each row is an
EligibleCategoryRow.- Parameters:
profile (
UsageRatioProfile) – The operator’s persisted per-category overrides.year (
int) – Filing year whose category profiles supply the statutory default ratio. Required rather than defaulted: the default ratio is year-versioned regulatory data, and a pinned year would apply one year’s law to every filing.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used for every category and governed-fact query in this projection.
- Return type:
- validate_ratios_profile(*, bucket_id, profile, operation, require_overrides_for=())[source]¶
Inspect a profile against eligibility and any required overrides.
require_overrides_foris the set of categories the caller needs explicitly populated (e.g. a modelo’s pre-calculate readiness check). Categories absent fromELIGIBLE_USAGE_RATIO_CATEGORIESraise anot_eligiblefinding rather than silently passing.Returns a
RatiosValidationReport.- Return type:
- Parameters:
bucket_id (str)
profile (UsageRatioProfile)
operation (PinnedAuthorityOperation)
require_overrides_for (tuple[SpendingCategory, ...])
- list_eligible_ratios_for_bucket(*, bucket_id, year, operation)[source]¶
Convenience: load the bucket’s profile and project the eligibility report.
Each element is an
EligibleCategoryRowdescribing one spending category’s eligibility and configured ratio.- Parameters:
bucket_id (
str) – The bucket whose persisted profile is projected.year (
int) – Filing year whose category profiles supply the statutory default ratio.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used to decode the stored profile.
- Return type:
- validate_ratios_for_bucket(*, bucket_id, operation, require_overrides_for=())[source]¶
Load the bucket’s profile, run validation, and return a
RatiosValidationReport.- Return type:
- Parameters:
bucket_id (str)
operation (PinnedAuthorityOperation)
require_overrides_for (tuple[SpendingCategory, ...])
- set_usage_ratio(*, bucket_id, category, ratio, operation)[source]¶
Set or replace one per-category usage-ratio override on the bucket.
Loads the bucket’s
UsageRatioProfile, applies the override through the domainwith_ratiovalidator, and persists the result. Returns the prior override value for the category (Nonewhen there was none) so the caller can emit a before/after audit event. Application command boundary for the CLIledger ratios setverb; the CLI no longer calls the domain load/save primitives directly.The load-modify-save runs under the per-bucket
cadrumo.domain.usage_ratios.service.usage_ratio_bucket_lock()so two concurrent writers cannot read the same snapshot and lose one another’s override.- Return type:
- Parameters:
bucket_id (str)
category (SpendingCategory)
ratio (Decimal)
operation (PinnedAuthorityOperation)
- unset_usage_ratio(*, bucket_id, category, operation)[source]¶
Clear one per-category usage-ratio override on the bucket.
Returns the cleared value. Raises
UsageRatioValidationErrorwhen the category carries no persisted override (so the caller can surface a precise “nothing to clear” message). Application command boundary for the CLIledger ratios unsetverb.The load-modify-save runs under the per-bucket
cadrumo.domain.usage_ratios.service.usage_ratio_bucket_lock()so a concurrentseton a sibling category cannot be lost by this clear.- Return type:
- Parameters:
bucket_id (str)
category (SpendingCategory)
operation (PinnedAuthorityOperation)
- class RatiosCensoOverrideWarning(**data)[source]¶
Bases:
BaseModelA non-fatal warning that the operator’s per-category override deviates from the censo-derived value.
The censo is the binding legal source of truth for censo-derived ratios. Operators may still override (e.g. to model a planned afectación change), but the engine emits a typed warning so downstream auditors can review the divergence.
- Parameters:
data (Any)
- category: SpendingCategory¶
- override_ratio: UnitProportion¶
- censo_derived_ratio: UnitProportion¶
- raw_afectacion_ratio: UnitProportion¶
- censo_business_pct_for(category, raw_afectacion_ratio, *, year, operation)[source]¶
Return the legally-effective business_pct for a category from censo.
The per-category projection of
cadrumo.domain.usage_ratios.service.derive_home_office_ratios_from_censo(): given a singleSpendingCategoryand the operator’s bound censooffice_m2 / total_m2, returns theraw_afectacion_ratio * statutory_multipliervalue the classify and allocate paths should stamp ontoTransaction.business_pctwhen no operator override is present. ReturnsNonefor categories outside the HOME_OFFICE families or when no censo has been applied yet, signalling to the caller that the operator’s explicit value (or the registry default) governs instead.- Return type:
- Parameters:
category (SpendingCategory)
raw_afectacion_ratio (Decimal | None)
year (int)
operation (PinnedAuthorityOperation)
Bases:
StrEnumWhy a row did or did not receive a censo-derived business share.
Five members because the four ways of NOT deriving one are different facts about the taxpayer, and a caller that could only see
Nonehad to guess which. Only two of them are anything the operator can act on.The operator supplied a share; no profile fact is consulted.
The censo fact and the category’s statutory rule produced one.
No category, so there is nothing to apportion against.
No censo has been applied yet, so the afectación ratio is unknown.
The category is outside the home-office families and is never apportioned by censo, whatever the taxpayer declared.
Bases:
BaseModelOne resolution: what decided the share, and the share if there is one.
- Parameters:
data (Any)
Decide the business share a row is stamped with, and say why.
The legal arithmetic is
censo_business_pct_for(); this is the precedence around it, which was a chain of early returns at a command boundary and is therefore the half a second frontend had to reproduce.The order is the rule. An operator statement wins over every profile fact, because it is the specific claim and the censo is only ever a default. Absence of a category is asked before absence of a censo: a row with no category has nothing to apportion whether or not a censo exists, and reporting the censo as the obstacle would send the operator to fix the wrong thing.
censo_afectacion_ratiois passed in rather than read here so this stays a decision about facts. WHICH profile is active, and whether one is active at all, is a session question the caller already answers.- Parameters:
operator_supplied (
Decimal|None) – The share the operator stated, orNone.category (
SpendingCategory|None) – The row’s spending category, orNonewhen unset.censo_afectacion_ratio (
Decimal|None) – The boundoffice_m2 / total_m2from the applied censo, orNonewhen none has been applied.year (
int) – The filing year whose category profiles supply the statutory multiplier. Year-versioned regulatory data, so it comes from the row’s own booked date rather than a pinned literal.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used for category family and proportionality resolution.
- Return type:
- Returns:
The resolution, carrying a share only where one was decided.
- censo_override_warning(*, category, override_ratio, raw_afectacion_ratio, year, operation)[source]¶
Return a typed warning when an override deviates from the censo.
The check is silent for non-HOME_OFFICE categories: only the suministros and ownership home-office families are legally bound to the censo-derived afectación ratio (LIRPF Art. 30.2 rule 5, Ley 6/2017 BOE-A-2017-12544). For HOME_OFFICE categories the helper computes the legally-effective ratio (raw afectación times the rule’s
statutory_multiplier) and compares it againstoverride_ratiofor exact equality. A non-equal pair returns aRatiosCensoOverrideWarning; equal values (and non-home-office categories) returnNone.- Parameters:
category (
SpendingCategory) – The category being overridden viaratios set.override_ratio (
Decimal) – The operator-supplied override.raw_afectacion_ratio (
Decimal) –office_m2 / total_m2from the bound censo snapshot.year (
int) – Registry year whose proportionality rule drives the derivation.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used for category family and proportionality resolution.
- Return type:
- Returns:
A
RatiosCensoOverrideWarningif a warning should be emitted, otherwiseNone.
- class UsageRatioMutationOutcomeV1(**data)[source]¶
Bases:
BaseModelWhat one ratio mutation changed, and what it raised against the Censo.
- Parameters:
data (Any)
- category: SpendingCategory¶
- prior_ratio: Decimal | None¶
- new_ratio: Decimal | None¶
- censo_override_warning: RatiosCensoOverrideWarning | None¶
- apply_usage_ratio_override(*, bucket_id, category, ratio, year, profile_id=None, raw_afectacion_ratio=None, operation)[source]¶
Persist one override, record it, and check it against the Censo.
Three things that had to happen together and were composed by the caller: the write, its audit event, and the comparison against the afectación ratio the operator declared to the AEAT. A surface that performed the write and forgot the comparison would let an override silently contradict the Censo.
NOT ATOMIC, and deliberately reported rather than papered over: the ratio store and the event history are separate secure objects with no shared commit, so a failure after the write leaves a persisted override with no audit event. Making it atomic needs the co-commit treatment the invoice link writer uses; this function does not invent one.
- Parameters:
bucket_id (
str) – The owning profile bucket.category (
SpendingCategory) – The spending category being overridden.ratio (
Decimal) – The override to store.year (
int) – The filing year the Censo comparison is made for.profile_id (
str|None) – The active profile, when one is bound.raw_afectacion_ratio (
Decimal|None) – The Censo-declared afectación ratio, when known.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used to decode the stored profile.
- Return type:
- Returns:
The prior and new values, plus any Censo override warning raised.
- clear_usage_ratio_override(*, bucket_id, category, operation)[source]¶
Clear one override and record the clearance.
Carries the same non-atomicity as
apply_usage_ratio_override().- Parameters:
bucket_id (
str) – The owning profile bucket.category (
SpendingCategory) – The category whose override is cleared.operation (
PinnedAuthorityOperation) – The caller-owned authority generation used to decode the stored profile.
- Return type:
- Returns:
The cleared value as
prior_ratio, withnew_ratioabsent.- Raises:
UsageRatioValidationError – When the category carries no override.