Update dashboard: split scheduled by method, outstanding checks with 90-day buckets, remove cleared section

This commit is contained in:
Adam Moussa 2026-04-10 17:35:47 -04:00
parent 3b8c201444
commit 7d1686bf94

View file

@ -104,11 +104,13 @@ function buildHomeView(payments, metadata) {
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
// Categorize payments // Categorize payments
const scheduled = []; // future payments not yet due const scheduledChecks = [];
const outstanding = []; // past-due checks not yet cleared, or returned by BoA const scheduledACH = [];
const cleared = []; // confirmed cleared by BoA or ACH past due date const outstandingChecks = [];
const skipStatuses = ["voided", "cancelled"]; const skipStatuses = ["voided", "cancelled", "canceled", "marked as void", "cleared"];
const ninetyDaysAgo = new Date(today);
ninetyDaysAgo.setDate(ninetyDaysAgo.getDate() - 90);
for (const p of payments) { for (const p of payments) {
if (p.method !== "ACH" && p.method !== "Check") continue; if (p.method !== "ACH" && p.method !== "Check") continue;
@ -116,21 +118,16 @@ function buildHomeView(payments, metadata) {
const dt = parseMDYLocal(p.send_payment_on); const dt = parseMDYLocal(p.send_payment_on);
if (!dt) continue; if (!dt) continue;
// Skip voided/cancelled payments entirely const status = (p.status || "").toLowerCase();
if (skipStatuses.includes((p.status || "").toLowerCase())) continue; if (skipStatuses.includes(status)) continue;
if (p.clear_status === "Returned") { if (dt >= today) {
outstanding.push(p); // Future — scheduled
} else if (p.clear_status === "Cleared") { if (p.method === "Check") scheduledChecks.push(p);
cleared.push(p); else scheduledACH.push(p);
} else if (p.method === "ACH" && dt < today) { } else if (p.method === "Check") {
// ACH assumed cleared once past due date // Past-due check not cleared — outstanding
cleared.push(p); outstandingChecks.push(p);
} else if (dt < today) {
// Check past due date but not yet confirmed by BoA
outstanding.push(p);
} else {
scheduled.push(p);
} }
} }
@ -140,11 +137,14 @@ function buildHomeView(payments, metadata) {
const db = parseMDYLocal(b.send_payment_on); const db = parseMDYLocal(b.send_payment_on);
return (da || 0) - (db || 0); return (da || 0) - (db || 0);
}; };
scheduled.sort(byDate); scheduledChecks.sort(byDate);
outstanding.sort(byDate); scheduledACH.sort(byDate);
cleared.sort(byDate);
const buildSectionBlocks = (title, emoji, items) => { // Split outstanding into <=90 days and >90 days
const outstanding90 = outstandingChecks.filter((p) => parseMDYLocal(p.send_payment_on) >= ninetyDaysAgo);
const outstandingOver90 = outstandingChecks.filter((p) => parseMDYLocal(p.send_payment_on) < ninetyDaysAgo);
const buildScheduledBlocks = (title, emoji, items) => {
const total = items.reduce((sum, p) => sum + p.amount_usd, 0); const total = items.reduce((sum, p) => sum + p.amount_usd, 0);
const blocks = [ const blocks = [
@ -197,6 +197,52 @@ function buildHomeView(payments, metadata) {
return blocks; return blocks;
}; };
const buildOutstandingBlocks = () => {
const totalAll = outstandingChecks.reduce((sum, p) => sum + p.amount_usd, 0);
const blocks = [
{
type: "section",
text: {
type: "mrkdwn",
text: `*:warning: Outstanding Checks*\n${outstandingChecks.length} checks • ${formatCurrency(totalAll)}`,
},
},
{ type: "divider" },
];
if (!outstandingChecks.length) {
blocks.push({
type: "section",
text: { type: "mrkdwn", text: "_None_" },
});
blocks.push({ type: "divider" });
return blocks;
}
const total90 = outstanding90.reduce((sum, p) => sum + p.amount_usd, 0);
const totalOver90 = outstandingOver90.reduce((sum, p) => sum + p.amount_usd, 0);
blocks.push({
type: "section",
fields: [
{ type: "mrkdwn", text: `*90 days or less*` },
{ type: "mrkdwn", text: `${outstanding90.length} checks • ${formatCurrency(total90)}` },
],
});
blocks.push({
type: "section",
fields: [
{ type: "mrkdwn", text: `*Over 90 days*` },
{ type: "mrkdwn", text: `${outstandingOver90.length} checks • ${formatCurrency(totalOver90)}` },
],
});
blocks.push({ type: "divider" });
return blocks;
};
return { return {
type: "home", type: "home",
blocks: [ blocks: [
@ -212,9 +258,9 @@ function buildHomeView(payments, metadata) {
], ],
}, },
{ type: "divider" }, { type: "divider" },
...buildSectionBlocks("Scheduled", ":calendar:", scheduled), ...buildScheduledBlocks("Scheduled Checks", ":calendar:", scheduledChecks),
...buildSectionBlocks("Outstanding", ":warning:", outstanding), ...buildScheduledBlocks("Scheduled ACH", ":calendar:", scheduledACH),
...buildSectionBlocks("Cleared", ":white_check_mark:", cleared), ...buildOutstandingBlocks(),
], ],
}; };
} }