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>
This commit is contained in:
parent
4506231f02
commit
0cf311bdf4
1 changed files with 23 additions and 8 deletions
|
|
@ -5,7 +5,7 @@ use crate::euros::Euros;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Error, Clone)]
|
#[derive(Debug, PartialEq, Eq, Error, Clone)]
|
||||||
pub enum LoanOfferError {
|
pub enum LoanOfferError {
|
||||||
#[error("loan cannot have a negative interest rate: {0}%")]
|
#[error("loan cannot have a negative interest rate: {0}")]
|
||||||
NegativeInterestRate(Decimal),
|
NegativeInterestRate(Decimal),
|
||||||
#[error("loan duration cannot be zero")]
|
#[error("loan duration cannot be zero")]
|
||||||
ZeroLoanDuration,
|
ZeroLoanDuration,
|
||||||
|
|
@ -16,18 +16,18 @@ pub enum LoanOfferError {
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct LoanOffer {
|
pub struct LoanOffer {
|
||||||
borrowed_capital: Euros,
|
borrowed_capital: Euros,
|
||||||
annual_rate_in_percent: Decimal,
|
annual_nominal_rate: Decimal,
|
||||||
loan_duration_in_months: u64,
|
loan_duration_in_months: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoanOffer {
|
impl LoanOffer {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
borrowed_capital: Euros,
|
borrowed_capital: Euros,
|
||||||
annual_rate_in_percent: Decimal,
|
annual_nominal_rate: Decimal,
|
||||||
loan_duration_in_months: u64,
|
loan_duration_in_months: u64,
|
||||||
) -> Result<Self, LoanOfferError> {
|
) -> Result<Self, LoanOfferError> {
|
||||||
if annual_rate_in_percent < Decimal::ZERO {
|
if annual_nominal_rate < Decimal::ZERO {
|
||||||
Err(LoanOfferError::NegativeInterestRate(annual_rate_in_percent))
|
Err(LoanOfferError::NegativeInterestRate(annual_nominal_rate))
|
||||||
} else if loan_duration_in_months == 0 {
|
} else if loan_duration_in_months == 0 {
|
||||||
Err(LoanOfferError::ZeroLoanDuration)
|
Err(LoanOfferError::ZeroLoanDuration)
|
||||||
} else if borrowed_capital <= Euros::from_cents_as_i64(0) {
|
} else if borrowed_capital <= Euros::from_cents_as_i64(0) {
|
||||||
|
|
@ -35,11 +35,15 @@ impl LoanOffer {
|
||||||
} else {
|
} else {
|
||||||
Ok(LoanOffer {
|
Ok(LoanOffer {
|
||||||
borrowed_capital,
|
borrowed_capital,
|
||||||
annual_rate_in_percent,
|
annual_nominal_rate,
|
||||||
loan_duration_in_months,
|
loan_duration_in_months,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn annual_nominal_rate_in_percent(&self) -> Decimal {
|
||||||
|
self.annual_nominal_rate * Decimal::ONE_HUNDRED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -92,7 +96,7 @@ mod tests {
|
||||||
ret,
|
ret,
|
||||||
Ok(LoanOffer {
|
Ok(LoanOffer {
|
||||||
borrowed_capital: Euros::from_cents_as_i64(10),
|
borrowed_capital: Euros::from_cents_as_i64(10),
|
||||||
annual_rate_in_percent: Decimal::new(45, 2),
|
annual_nominal_rate: Decimal::new(45, 2),
|
||||||
loan_duration_in_months: 15
|
loan_duration_in_months: 15
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
@ -105,9 +109,20 @@ mod tests {
|
||||||
ret,
|
ret,
|
||||||
Ok(LoanOffer {
|
Ok(LoanOffer {
|
||||||
borrowed_capital: Euros::from_cents_as_i64(10),
|
borrowed_capital: Euros::from_cents_as_i64(10),
|
||||||
annual_rate_in_percent: Decimal::ZERO,
|
annual_nominal_rate: Decimal::ZERO,
|
||||||
loan_duration_in_months: 15
|
loan_duration_in_months: 15
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn conversion_to_annual_nominal_rate_in_percent_works() {
|
||||||
|
let offer = LoanOffer::new(
|
||||||
|
Euros::from_cents_as_i64(150_000_00),
|
||||||
|
Decimal::new(4, 4),
|
||||||
|
300,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(offer.annual_nominal_rate_in_percent(), Decimal::new(4, 2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue