From b2eed3e75a2354c394eedeee6e5c4309eebad040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Thu, 16 Apr 2026 23:02:37 -0400 Subject: [PATCH] fix(budget-policy-input): convert dollars to cents via string parsing (P2-35) Avoid floating-point drift from parseFloat * 100 by parsing digits then concatenating; dollarsToCents returns null for invalid input. --- src/renderer/lib/budget-policy-input.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/renderer/lib/budget-policy-input.ts b/src/renderer/lib/budget-policy-input.ts index 8d69974e..f1c220cd 100644 --- a/src/renderer/lib/budget-policy-input.ts +++ b/src/renderer/lib/budget-policy-input.ts @@ -11,9 +11,25 @@ interface BuildBudgetPolicyInputArgs { notifyEnabled: boolean; } +/** + * Convert a dollar-string ("12.34") to integer cents without relying on float + * multiplication (which can lose precision, e.g. 0.29 * 100 = 28.9999...). + * Accepts optional sign, digits, and up to two fractional digits. + */ +function dollarsToCents(input: string): number | null { + const trimmed = input.trim(); + const match = /^-?(\d+)(?:\.(\d{1,2}))?$/.exec(trimmed); + if (!match) return null; + const whole = match[1]; + const fraction = (match[2] ?? "").padEnd(2, "0"); + const cents = Number.parseInt(whole + fraction, 10); + if (!Number.isFinite(cents)) return null; + return trimmed.startsWith("-") ? -cents : cents; +} + export function buildBudgetPolicyInput(args: BuildBudgetPolicyInputArgs) { - const amount = Math.round(Number.parseFloat(args.amountDollars) * 100); - if (!Number.isFinite(amount) || amount <= 0) { + const amount = dollarsToCents(args.amountDollars); + if (amount === null || amount <= 0) { return null; }