fix(match-suggestions): use rejection timestamps and share late attribution helper
This commit is contained in:
parent
99abca9868
commit
a97d656e92
|
|
@ -16,6 +16,18 @@ function merchantMatches(txMerchant, ruleMerchant) {
|
|||
wordBoundary(txMerchant).test(ruleMerchant);
|
||||
}
|
||||
|
||||
// Detects when a payment posted just after month end but the bill was due in the
|
||||
// prior month. Grace window: up to `graceDays` days into the new month.
|
||||
// Module-scoped so both applyMerchantRules and syncBillPaymentsFromSimplefin can use it.
|
||||
function lateAttributionCandidate(paidDateStr, dueDayOfMonth, graceDays = 5) {
|
||||
const paid = new Date(paidDateStr + 'T00:00:00');
|
||||
const dayOfMonth = paid.getDate();
|
||||
if (dayOfMonth > graceDays) return null;
|
||||
const prevMonthLastDay = new Date(paid.getFullYear(), paid.getMonth(), 0);
|
||||
if (dueDayOfMonth > prevMonthLastDay.getDate()) return null;
|
||||
return prevMonthLastDay.toISOString().slice(0, 10); // suggested prior-month date
|
||||
}
|
||||
|
||||
// Persist a merchant→bill rule so future synced transactions auto-match.
|
||||
function addMerchantRule(db, userId, billId, merchant) {
|
||||
const normalized = normalizeMerchant(merchant);
|
||||
|
|
@ -35,17 +47,6 @@ function addMerchantRule(db, userId, billId, merchant) {
|
|||
// merchant rules, create payments, and mark the transactions matched.
|
||||
// Returns { matched: number }.
|
||||
function applyMerchantRules(db, userId) {
|
||||
// Detects when a payment posted just after month end but the bill was due in the prior month.
|
||||
// Grace window: up to LATE_ATTR_DAYS days into the new month.
|
||||
function lateAttributionCandidate(paidDateStr, dueDayOfMonth, graceDays = 5) {
|
||||
const paid = new Date(paidDateStr + 'T00:00:00');
|
||||
const dayOfMonth = paid.getDate();
|
||||
if (dayOfMonth > graceDays) return null;
|
||||
const prevMonthLastDay = new Date(paid.getFullYear(), paid.getMonth(), 0);
|
||||
if (dueDayOfMonth > prevMonthLastDay.getDate()) return null;
|
||||
return prevMonthLastDay.toISOString().slice(0, 10); // suggested prior-month date
|
||||
}
|
||||
|
||||
let rules;
|
||||
try {
|
||||
rules = db.prepare(`
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ async function runAllCleanup() {
|
|||
// Prune match suggestion rejections older than 90 days
|
||||
try {
|
||||
const { changes } = getDb().prepare(
|
||||
"DELETE FROM match_suggestion_rejections WHERE created_at <= datetime('now', '-90 days')"
|
||||
"DELETE FROM match_suggestion_rejections WHERE rejected_at <= datetime('now', '-90 days')"
|
||||
).run();
|
||||
tasks.suggestion_rejections = { pruned: changes };
|
||||
} catch { tasks.suggestion_rejections = { pruned: 0 }; }
|
||||
|
|
|
|||
|
|
@ -226,23 +226,13 @@ function loadBills(db, userId) {
|
|||
}
|
||||
|
||||
function loadRejections(db, userId) {
|
||||
try {
|
||||
const rows = db.prepare(`
|
||||
SELECT transaction_id, bill_id
|
||||
FROM match_suggestion_rejections
|
||||
WHERE user_id = ?
|
||||
AND created_at > datetime('now', '-90 days')
|
||||
`).all(userId);
|
||||
return new Set(rows.map(row => suggestionId(row.transaction_id, row.bill_id)));
|
||||
} catch {
|
||||
// Fall back to all rejections if created_at column doesn't exist yet
|
||||
try {
|
||||
const rows = db.prepare(`
|
||||
SELECT transaction_id, bill_id FROM match_suggestion_rejections WHERE user_id = ?
|
||||
`).all(userId);
|
||||
return new Set(rows.map(row => suggestionId(row.transaction_id, row.bill_id)));
|
||||
} catch { return new Set(); }
|
||||
}
|
||||
const rows = db.prepare(`
|
||||
SELECT transaction_id, bill_id
|
||||
FROM match_suggestion_rejections
|
||||
WHERE user_id = ?
|
||||
AND rejected_at > datetime('now', '-90 days')
|
||||
`).all(userId);
|
||||
return new Set(rows.map(row => suggestionId(row.transaction_id, row.bill_id)));
|
||||
}
|
||||
|
||||
function loadPriorMatchKeys(db, userId) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue