From 0daec80461cbfb159b6ac7a04102fd4f6840e352 Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Tue, 21 Jul 2026 19:24:11 -0400 Subject: [PATCH] fix(csv): comma-tolerant amount parsing in backfill (PR #72 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Number() on a hand-inserted comma-formatted string amount would NaN and skip the check during backfill; hoist the CSV path's parseAmount to module scope and share it. No live records are affected (all amount_usd values are DDB Number type) — defensive consistency. --- src/processPaymentCsv.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/processPaymentCsv.js b/src/processPaymentCsv.js index bdef651..bb29558 100644 --- a/src/processPaymentCsv.js +++ b/src/processPaymentCsv.js @@ -44,6 +44,13 @@ async function getAccessToken(applicationID, clientId, clientSecret) { // CloudWatch log lines (CWE-117). const logSafe = (v) => JSON.stringify(String(v ?? "").slice(0, 64)); +// Comma-tolerant amount parsing, shared by the CSV path and the backfill so +// a hand-inserted "1,234.56" string record can't NaN out of registration. +const parseAmount = (value) => { + const num = parseFloat(String(value || "0").replace(/,/g, "").trim()); + return isNaN(num) ? 0 : num; +}; + async function backfillBoA() { const cancelStatuses = ["voided", "cancelled", "canceled", "marked as void"]; @@ -82,7 +89,7 @@ async function backfillBoA() { if (cancelStatuses.includes((item.status || "").toLowerCase())) continue; if (item.check_number.length > 10) continue; const issueDate = toISODate(item.send_payment_on); - const amount = Number(item.amount_usd); + const amount = parseAmount(item.amount_usd); if (!issueDate || !(amount > 0)) { console.error(`Backfill skipping check ${logSafe(item.check_number)}: missing issue date or amount`); continue; @@ -256,11 +263,6 @@ export const handler = async (event) => { return clean; }); - const parseAmount = (value) => { - const num = parseFloat(String(value || "0").replace(/,/g, "").trim()); - return isNaN(num) ? 0 : num; - }; - const cancelStatuses = ["voided", "cancelled", "canceled", "marked as void"]; // Status progression ranks — higher number = further along in lifecycle