Skip to content

Commit

Permalink
simplify interest voptions
Browse files Browse the repository at this point in the history
  • Loading branch information
simontreanor committed Sep 12, 2024
1 parent fb679a4 commit 6afe05b
Show file tree
Hide file tree
Showing 12 changed files with 88 additions and 94 deletions.
18 changes: 9 additions & 9 deletions src/Amortisation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ module Amortisation =
/// the portion of the net effect assigned to the charges
ChargesPortion: int64<Cent>
/// the simple interest initially calculated at the start date
OriginalSimpleInterest: decimal<Cent> voption
OriginalSimpleInterest: decimal<Cent>
/// the interest initially calculated according to the interest method at the start date
ContractualInterest: decimal<Cent>
/// the simple interest accruable between the previous amortisation day and the current day
Expand Down Expand Up @@ -94,7 +94,7 @@ module Amortisation =
NetEffect = 0L<Cent>
PaymentStatus = NoneScheduled
BalanceStatus = OpenBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 0m<Cent>
NewInterest = 0m<Cent>
Expand Down Expand Up @@ -242,7 +242,7 @@ module Amortisation =

let advances = if ap.AppliedPaymentDay = 0<OffsetDay> then [| sp.Principal |] else [||] // note: assumes single advance on day 0

let contractualInterest = ap.ContractualInterest |> ValueOption.defaultValue 0m<Cent>
let contractualInterest = ap.ContractualInterest

let simpleInterest =
if si.PrincipalBalance <= 0L<Cent> then
Expand All @@ -262,13 +262,13 @@ module Amortisation =
let a' =
{ a with
CumulativeSimpleInterest = a.CumulativeSimpleInterest + cappedSimpleInterest
CumulativeOriginalSimpleInterest = a.CumulativeOriginalSimpleInterest + (ap.OriginalSimpleInterest |> ValueOption.defaultValue 0m<Cent>)
CumulativeOriginalSimpleInterest = a.CumulativeOriginalSimpleInterest + ap.OriginalSimpleInterest
}

let newInterest =
match sp.Interest.Method with
| Interest.Method.AddOn ->
(ap.OriginalSimpleInterest |> ValueOption.defaultValue 0m<Cent>) - cappedSimpleInterest
ap.OriginalSimpleInterest - cappedSimpleInterest
// (* if ap.OriginalSimpleInterest.IsSome || ap.AppliedPaymentDay = finalAppliedPaymentDay then *) a'.CumulativeSimpleInterest - a'.CumulativeOriginalSimpleInterest (* else 0m<Cent> *)
| Interest.Method.Simple ->
simpleInterest
Expand Down Expand Up @@ -654,15 +654,15 @@ module Amortisation =
OriginalSimpleInterest =
match scheduleType, sp.Interest.Method with
| ScheduleType.Original, Interest.Method.AddOn ->
ValueSome si.SimpleInterest
si.SimpleInterest
| _ ->
ValueNone
0m<Cent>
ContractualInterest =
match scheduleType, sp.Interest.Method with
| ScheduleType.Original, Interest.Method.AddOn ->
si.InterestPortion |> Cent.toDecimalCent |> ValueSome
si.InterestPortion |> Cent.toDecimalCent
| _ ->
ValueNone
0m<Cent>
}), s.InitialInterestBalance
| ValueNone ->
[||], 0L<Cent>
Expand Down
30 changes: 12 additions & 18 deletions src/AppliedPayment.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ module AppliedPayment =
/// the payment status based on the payments made on the current day
PaymentStatus: CustomerPaymentStatus
/// the simple interest initially calculated at the start date
OriginalSimpleInterest: decimal<Cent> voption
OriginalSimpleInterest: decimal<Cent>
/// the interest initially calculated according to the interest method at the start date
ContractualInterest: decimal<Cent> voption
ContractualInterest: decimal<Cent>
}

/// groups payments by day, applying actual payments, adding a payment status and optionally a late payment charge if underpaid
Expand Down Expand Up @@ -126,24 +126,18 @@ module AppliedPayment =
| AllChargesApplied -> cc

let originalSimpleInterest =
let ii = payments |> Array.map (_.OriginalSimpleInterest >> toOption)
if ii |> Array.isEmpty || ii |> Array.forall _.IsNone then
ValueNone
let ii = payments |> Array.map _.OriginalSimpleInterest
if ii |> Array.isEmpty || ii |> Array.forall ((=) 0m<Cent>) then
0m<Cent>
else
ii
|> Array.choose id
|> Array.sum
|> ValueSome
Array.sum ii

let contractualInterest =
let ii = payments |> Array.map (_.ContractualInterest >> toOption)
if ii |> Array.isEmpty || ii |> Array.forall _.IsNone then
ValueNone
let ii = payments |> Array.map _.ContractualInterest
if ii |> Array.isEmpty || ii |> Array.forall ((=) 0m<Cent>) then
0m<Cent>
else
ii
|> Array.choose id
|> Array.sum
|> ValueSome
Array.sum ii

{
AppliedPaymentDay = offsetDay
Expand Down Expand Up @@ -172,8 +166,8 @@ module AppliedPayment =
IncurredCharges = [||]
NetEffect = 0L<Cent>
PaymentStatus = paymentStatus
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
payments
|> Array.append [| newAppliedPayment |]
Expand Down
28 changes: 14 additions & 14 deletions src/CustomerPayments.fs
Original file line number Diff line number Diff line change
Expand Up @@ -89,52 +89,52 @@ module CustomerPayments =
/// the details of the payment
PaymentDetails: CustomerPaymentDetails
/// the original simple interest
OriginalSimpleInterest: decimal<Cent> voption
OriginalSimpleInterest: decimal<Cent>
/// the original, contractually calculated interest
ContractualInterest: decimal<Cent> voption
ContractualInterest: decimal<Cent>
}
with
static member ScheduledOriginal paymentDay amount =
{
PaymentDay = paymentDay
PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Original amount; Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
static member ScheduledRescheduled paymentDay amount =
{
PaymentDay = paymentDay
PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Rescheduled amount; Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
static member ActualConfirmed paymentDay amount =
{
PaymentDay = paymentDay
PaymentDetails = ActualPayment { ActualPaymentStatus = ActualPaymentStatus.Confirmed amount; Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
static member ActualPending paymentDay amount =
{
PaymentDay = paymentDay
PaymentDetails = ActualPayment { ActualPaymentStatus = ActualPaymentStatus.Pending amount; Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
static member ActualFailed paymentDay amount charges =
{
PaymentDay = paymentDay
PaymentDetails = ActualPayment { ActualPaymentStatus = ActualPaymentStatus.Failed (amount, charges); Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}
static member ActualWriteOff paymentDay amount =
{
PaymentDay = paymentDay
PaymentDetails = ActualPayment { ActualPaymentStatus = ActualPaymentStatus.WriteOff amount; Metadata = Map.empty }
OriginalSimpleInterest = ValueNone
ContractualInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
}

/// the status of a payment made by the customer
Expand Down
6 changes: 3 additions & 3 deletions src/Rescheduling.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ module Rescheduling =
| ValueSome s ->
s.Items
|> Array.filter(fun si -> si.Payment.IsSome)
|> Array.map(fun si -> { PaymentDay = si.Day; PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Rescheduled si.Payment.Value; Metadata = Map.empty }; OriginalSimpleInterest = ValueNone; ContractualInterest = ValueNone })
|> Array.map(fun si -> { PaymentDay = si.Day; PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Rescheduled si.Payment.Value; Metadata = Map.empty }; OriginalSimpleInterest = 0m<Cent>; ContractualInterest = 0m<Cent> })
| ValueNone ->
[||]
| RegularFixedSchedule regularFixedSchedules ->
regularFixedSchedules
|> Array.map(fun rfs ->
UnitPeriod.generatePaymentSchedule rfs.PaymentCount ValueNone UnitPeriod.Direction.Forward rfs.UnitPeriodConfig
|> Array.map(fun d -> { PaymentDay = OffsetDay.fromDate sp.StartDate d; PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Rescheduled rfs.PaymentAmount; Metadata = Map.empty }; OriginalSimpleInterest = ValueNone; ContractualInterest = ValueNone })
|> Array.map(fun d -> { PaymentDay = OffsetDay.fromDate sp.StartDate d; PaymentDetails = ScheduledPayment { ScheduledPaymentType = ScheduledPaymentType.Rescheduled rfs.PaymentAmount; Metadata = Map.empty }; OriginalSimpleInterest = 0m<Cent>; ContractualInterest = 0m<Cent> })
)
|> Array.concat
| IrregularSchedule payments ->
Expand All @@ -62,7 +62,7 @@ module Rescheduling =
quote.RevisedSchedule.ScheduleItems
|> Array.filter _.ScheduledPayment.IsSome
|> Array.filter(fun si -> si.OffsetDate < sp.AsOfDate)
|> Array.map(fun si -> { PaymentDay = si.OffsetDay; PaymentDetails = ScheduledPayment si.ScheduledPayment; OriginalSimpleInterest = si.OriginalSimpleInterest; ContractualInterest = ValueSome si.ContractualInterest })
|> Array.map(fun si -> { PaymentDay = si.OffsetDay; PaymentDetails = ScheduledPayment si.ScheduledPayment; OriginalSimpleInterest = si.OriginalSimpleInterest; ContractualInterest = si.ContractualInterest })
// configure the parameters for the new schedule
let spNew =
{ sp with
Expand Down
20 changes: 10 additions & 10 deletions tests/ActualPaymentTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ module ActualPaymentTests =
NetEffect = paymentAmount
PaymentStatus = PaymentMade
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = contractualInterest
SimpleInterest = interestAdjustment
NewInterest = interestAdjustment
Expand Down Expand Up @@ -280,7 +280,7 @@ module ActualPaymentTests =
NetEffect = 1193_95L<Cent>
PaymentStatus = ExtraPayment
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 26_75.760m<Cent>
NewInterest = 26_75.760m<Cent>
Expand Down Expand Up @@ -360,7 +360,7 @@ module ActualPaymentTests =
NetEffect = 1474_59L<Cent>
PaymentStatus = ExtraPayment
BalanceStatus = RefundDue
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 26_75.760m<Cent>
NewInterest = 26_75.760m<Cent>
Expand Down Expand Up @@ -445,7 +445,7 @@ module ActualPaymentTests =
NetEffect = -280_64L<Cent>
PaymentStatus = Refunded
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 0m<Cent>
NewInterest = 0m<Cent>
Expand Down Expand Up @@ -527,7 +527,7 @@ module ActualPaymentTests =
NetEffect = 1500_00L<Cent>
PaymentStatus = ExtraPayment
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 0m<Cent>
NewInterest = 0m<Cent>
Expand Down Expand Up @@ -612,7 +612,7 @@ module ActualPaymentTests =
NetEffect = 243_66L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 24_54.144m<Cent>
NewInterest = 24_54.144m<Cent>
Expand Down Expand Up @@ -697,7 +697,7 @@ module ActualPaymentTests =
NetEffect = -280_83L<Cent>
PaymentStatus = Refunded
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = -18.45304110M<Cent>
NewInterest = -18.45304110M<Cent>
Expand Down Expand Up @@ -781,7 +781,7 @@ module ActualPaymentTests =
NetEffect = 491_53L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 89_95.392m<Cent>
NewInterest = 89_95.392m<Cent>
Expand Down Expand Up @@ -865,7 +865,7 @@ module ActualPaymentTests =
NetEffect = 491_53L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = OpenBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 118_33.696m<Cent>
NewInterest = 118_33.696m<Cent>
Expand Down Expand Up @@ -951,7 +951,7 @@ module ActualPaymentTests =
NetEffect = 500_00L<Cent>
PaymentStatus = Overpayment
BalanceStatus = RefundDue
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 79_07.200m<Cent>
NewInterest = 79_07.200m<Cent>
Expand Down
16 changes: 8 additions & 8 deletions tests/ActualPaymentTestsExtra.fs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ module ActualPaymentTestsExtra =
NetEffect = 407_64L<Cent>
PaymentStatus = PaymentMade
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 3_30.67257534m<Cent>
NewInterest = 3_30.67257534m<Cent>
Expand Down Expand Up @@ -476,7 +476,7 @@ module ActualPaymentTestsExtra =
NetEffect = 170_04L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 64.65046575m<Cent>
NewInterest = 64.65046575m<Cent>
Expand Down Expand Up @@ -570,7 +570,7 @@ module ActualPaymentTestsExtra =
NetEffect = 9_80L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 3.72866027m<Cent>
NewInterest = 3.72866027m<Cent>
Expand Down Expand Up @@ -650,7 +650,7 @@ module ActualPaymentTestsExtra =
NetEffect = 137_36L<Cent>
PaymentStatus = PaymentMade
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 0m<Cent>
NewInterest = 0m<Cent>
Expand Down Expand Up @@ -730,7 +730,7 @@ module ActualPaymentTestsExtra =
NetEffect = 51_53L<Cent>
PaymentStatus = PaymentMade
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 9_43.040m<Cent>
NewInterest = 9_43.040m<Cent>
Expand Down Expand Up @@ -810,7 +810,7 @@ module ActualPaymentTestsExtra =
NetEffect = 142_40L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 1_28.41170136m<Cent>
NewInterest = 1_28.41170136m<Cent>
Expand Down Expand Up @@ -903,7 +903,7 @@ module ActualPaymentTestsExtra =
NetEffect = 18_71L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 7.11384109m<Cent>
NewInterest = 7.11384109m<Cent>
Expand Down Expand Up @@ -996,7 +996,7 @@ module ActualPaymentTestsExtra =
NetEffect = 18_71L<Cent>
PaymentStatus = NotYetDue
BalanceStatus = ClosedBalance
OriginalSimpleInterest = ValueNone
OriginalSimpleInterest = 0m<Cent>
ContractualInterest = 0m<Cent>
SimpleInterest = 7.11384109m<Cent>
NewInterest = 7.11384109m<Cent>
Expand Down
Loading

0 comments on commit 6afe05b

Please sign in to comment.