Commit graph

4 commits

Author SHA1 Message Date
Marcel Enguehard
8d00f6a936 Add LoanOffer::monthly_repayment
Closed form of the constant-instalment recurrence, C*i / (1 - (1+i)^-n), with
i the taux mensuel proportionnel (taux nominal / 12) rather than the taux
actuariel equivalent, which is what French lenders use for the schedule.

A zero rate is a real case, not a degenerate one: the PTZ is a 0 % loan and the
denominator collapses to zero, which rust_decimal's Div panics on rather than
erroring. The zero branch computes C/n, the limit of the formula as i tends to
zero, and offre_c_ptz covers it.

Both known-answer tests compare against generated fixtures whose values came
from a real amortisation table, not from this implementation.

The expect() is justified by the bounds from the previous commit: capital and
rate cap the value well below i64::MAX cents, and rescale(2) makes the scale
exact, so both EurosError arms are unreachable. CLAUDE.md is amended in the
same commit to permit expect() only in this provable case, since the rule
change exists for this call site.

Requires rust_decimal's maths feature for powu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 16:26:55 +02:00
Marcel Enguehard
91f96e7b57 Add LoanOffer with validating constructor
LoanOffer::new is the only way in: fields are private and the constructor
rejects a negative rate, a zero duration, and a non-positive capital. A zero
rate is accepted on purpose — the PTZ (prêt à taux zéro) is a real French
instrument.

Add thiserror for the typed error, as required for immo-core. Rate and
duration take no upper bound for now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 15:09:49 +02:00
Marcel Enguehard
68a9088ec4 Add Euros money type backed by integer cents
Store amounts as i64 cents rather than a Decimal, so the "scale is 2"
invariant is structural instead of maintained by hand. Both accessors are
total: as_cents is a field read, as_decimal derives the Decimal on demand.
i64 rather than u64 because differences between amounts can be negative.

Add rust_decimal, verified to build for wasm32-unknown-unknown with default
features. Allow clippy::inconsistent_digit_grouping in immo-core so cent
literals can be grouped as euros-then-cents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 11:22:41 +02:00
Marcel Enguehard
e5400c8992 Set up cargo workspace backbone
Two-crate workspace: immo-core for pure financial logic (wasm-compatible,
no async/IO deps) and immo-web for HTTP and rendering. Both crates are
still cargo-new skeletons; no domain code yet.

Pins the toolchain to 1.97 with rustfmt, clippy and the
wasm32-unknown-unknown target so the core crate's wasm constraint is
checkable locally. Cargo.lock is committed since the workspace ships a
binary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 20:30:55 +02:00