Commit graph

7 commits

Author SHA1 Message Date
Marcel Enguehard
0cf311bdf4 Store the annual nominal rate as a fraction, not a percentage
The field was called annual_rate_in_percent but nothing multiplied it by 100,
so a 3,41 % loan would have been stored as 3.41 and read as 341 %. Rename it
to annual_nominal_rate, which is what it holds, and add an explicit
annual_nominal_rate_in_percent() accessor for callers that want the display
form. Drop the trailing % from the error message, which was making the same
claim.

The nominal qualifier is there because TAEG will join this struct later and
the two must never be confused.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 15:17:15 +02:00
Marcel Enguehard
4506231f02 Rename Euros::from_cents to from_cents_as_i64
The constructor takes a raw i64 count of cents. Naming the unit at the call
site keeps it distinct from the Decimal-based constructor added next, where
the argument is an amount in euros rather than a cent count.

Also fixes a typo in a test name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 15:16:37 +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
f3d428dcbe Add Display for Euros
Renders as "123.45 €" — dot separator and a plain space, i.e. American
style. French formatting (narrow no-break space, comma separator) will need
a separate path since Display takes no parameters; deferred until there is
a page to render.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 15:09:34 +02:00
Marcel Enguehard
d812434827 Add zero known-answer test for Euros
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 11:26:04 +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