Skip to content
This repository is currently being migrated. It's locked while the migration is in progress.

Commit 75ce891

Browse files
committed
feat(26-8923): generate src/applications/benefits/26-8923/utils/irrrlCalculations.js via Optimus
1 parent 1811ea3 commit 75ce891

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Computes all 18 lines of VA Form 26-8923 from raw inputs.
3+
* Returns an object with all computed line values.
4+
* All monetary values are rounded to 2 decimal places at each line.
5+
* Line 18 is always rounded DOWN (Math.floor to cents) per form note.
6+
*
7+
* @param {Object} inputs
8+
* @param {number} inputs.line1ExistingLoanBalance
9+
* @param {number} inputs.line2CashPaymentFromVeteran
10+
* @param {number} inputs.line5DiscountPercent
11+
* @param {number} inputs.line6OriginationFeePercent
12+
* @param {number} inputs.line7FundingFeePercent
13+
* @param {number} inputs.line8OtherClosingCosts
14+
* @returns {Object} computed line values
15+
*/
16+
export function computeIRRRLWorksheet(inputs) {
17+
const {
18+
line1ExistingLoanBalance = 0,
19+
line2CashPaymentFromVeteran = 0,
20+
line5DiscountPercent = 0,
21+
line6OriginationFeePercent = 0,
22+
line7FundingFeePercent = 0.5,
23+
line8OtherClosingCosts = 0,
24+
} = inputs;
25+
26+
// Section I
27+
const line3Total = round2(line1ExistingLoanBalance - line2CashPaymentFromVeteran);
28+
29+
// Section II
30+
const line4CarryForward = line3Total;
31+
const line5DollarAmount = round2(line4CarryForward * (line5DiscountPercent / 100));
32+
const line6DollarAmount = round2(line4CarryForward * (line6OriginationFeePercent / 100));
33+
const line7DollarAmount = round2(line4CarryForward * (line7FundingFeePercent / 100));
34+
const line9PreliminaryTotal = round2(
35+
line4CarryForward +
36+
line5DollarAmount +
37+
line6DollarAmount +
38+
line7DollarAmount +
39+
line8OtherClosingCosts,
40+
);
41+
42+
// Section III
43+
const line10CarryForward = line9PreliminaryTotal;
44+
const line11DiscountOnLine10 = round2(
45+
line10CarryForward * (line5DiscountPercent / 100),
46+
);
47+
const line12Subtotal = round2(line10CarryForward + line11DiscountOnLine10);
48+
const line13SubtractLine5 = line5DollarAmount;
49+
const line14Subtotal = round2(line12Subtotal - line5DollarAmount);
50+
const line15SubtractLine7 = line7DollarAmount;
51+
const line16Subtotal = round2(line14Subtotal - line7DollarAmount);
52+
const line17FinalFundingFee = round2(
53+
line16Subtotal * (line7FundingFeePercent / 100),
54+
);
55+
const line18Raw = line16Subtotal + line17FinalFundingFee;
56+
57+
// Round DOWN always — never round up. Math.floor to nearest cent.
58+
const line18MaxLoanAmount = floorToCents(line18Raw);
59+
60+
// Rounding differential for the $50 recomputation warning
61+
const roundingDifferential = round2(line18Raw - line18MaxLoanAmount);
62+
63+
return {
64+
line3Total,
65+
line4CarryForward,
66+
line5DollarAmount,
67+
line6DollarAmount,
68+
line7DollarAmount,
69+
line9PreliminaryTotal,
70+
line10CarryForward,
71+
line11DiscountOnLine10,
72+
line12Subtotal,
73+
line13SubtractLine5,
74+
line14Subtotal,
75+
line15SubtractLine7,
76+
line16Subtotal,
77+
line17FinalFundingFee,
78+
line18MaxLoanAmount,
79+
roundingDifferential,
80+
};
81+
}
82+
83+
/**
84+
* Rounds to 2 decimal places using banker-safe method.
85+
* @param {number} value
86+
* @returns {number}
87+
*/
88+
export function round2(value) {
89+
return Math.round((value + Number.EPSILON) * 100) / 100;
90+
}
91+
92+
/**
93+
* Floors to nearest cent (always rounds DOWN per form note).
94+
* @param {number} value
95+
* @returns {number}
96+
*/
97+
export function floorToCents(value) {
98+
return Math.floor(value * 100) / 100;
99+
}
100+
101+
/**
102+
* Formats a number as a US dollar currency string.
103+
* @param {number|null} value
104+
* @returns {string}
105+
*/
106+
export function formatCurrency(value) {
107+
if (value === null || value === undefined || Number.isNaN(value)) {
108+
return '$0.00';
109+
}
110+
return new Intl.NumberFormat('en-US', {
111+
style: 'currency',
112+
currency: 'USD',
113+
}).format(value);
114+
}

0 commit comments

Comments
 (0)