2026-05-28 02:09:49 -05:00
|
|
|
|
'use strict';
|
|
|
|
|
|
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
import type { Dollars } from '../utils/money.mts';
|
|
|
|
|
|
import type { Db } from '../types/db';
|
|
|
|
|
|
|
|
|
|
|
|
const { accountingActiveSql } = require('./paymentAccountingService.cts');
|
|
|
|
|
|
// require(esm) of the branded money helpers; cast so fromCents keeps its
|
|
|
|
|
|
// Cents→Dollars signature (paymentValidation.cts uses the same pattern).
|
|
|
|
|
|
const { fromCents } = require('../utils/money.mts') as typeof import('../utils/money.mts');
|
|
|
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
|
interface PriorMonth {
|
|
|
|
|
|
y: number;
|
|
|
|
|
|
m: number;
|
|
|
|
|
|
key: string;
|
|
|
|
|
|
}
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
interface AmountSuggestion {
|
|
|
|
|
|
suggestion: Dollars | null;
|
|
|
|
|
|
months_used: number;
|
|
|
|
|
|
confidence: 'high' | 'low';
|
|
|
|
|
|
}
|
2026-06-07 01:05:48 -05:00
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
// The 6 calendar months immediately preceding (year, month), newest first, each
|
|
|
|
|
|
// as { y, m, key: 'YYYY-MM' }.
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
function priorMonths(year: number, month: number, count = 6): PriorMonth[] {
|
|
|
|
|
|
const list: PriorMonth[] = [];
|
2026-07-03 18:25:55 -05:00
|
|
|
|
let y = year;
|
|
|
|
|
|
let m = month;
|
|
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
|
|
|
|
m -= 1;
|
2026-07-06 14:23:53 -05:00
|
|
|
|
if (m === 0) {
|
|
|
|
|
|
m = 12;
|
|
|
|
|
|
y -= 1;
|
|
|
|
|
|
}
|
2026-07-03 18:25:55 -05:00
|
|
|
|
list.push({ y, m, key: `${y}-${String(m).padStart(2, '0')}` });
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Rolling median of a bill's monthly amounts → a suggestion object (or null).
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
function medianSuggestion(amounts: number[]): AmountSuggestion | null {
|
2026-07-03 18:25:55 -05:00
|
|
|
|
if (amounts.length === 0) return null;
|
|
|
|
|
|
const sorted = [...amounts].sort((a, b) => a - b);
|
|
|
|
|
|
const mid = Math.floor(sorted.length / 2);
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
2026-07-03 18:25:55 -05:00
|
|
|
|
return {
|
|
|
|
|
|
suggestion: fromCents(Math.round(median)),
|
|
|
|
|
|
months_used: amounts.length,
|
|
|
|
|
|
confidence: amounts.length >= 3 ? 'high' : 'low',
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 02:09:49 -05:00
|
|
|
|
/**
|
|
|
|
|
|
* Computes a suggested expected amount for a bill based on the rolling median
|
|
|
|
|
|
* of the last 6 months of actual data. Prefers monthly_bill_state.actual_amount
|
|
|
|
|
|
* (user-corrected values) over raw payment sums.
|
|
|
|
|
|
*/
|
2026-07-06 14:23:53 -05:00
|
|
|
|
function computeAmountSuggestion(
|
|
|
|
|
|
db: Db,
|
|
|
|
|
|
billId: number,
|
|
|
|
|
|
year: number,
|
|
|
|
|
|
month: number,
|
|
|
|
|
|
): AmountSuggestion | null {
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
const amounts: number[] = [];
|
2026-05-28 02:09:49 -05:00
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
for (const { y, m } of priorMonths(year, month, 6)) {
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const mbs = db
|
|
|
|
|
|
.prepare(
|
|
|
|
|
|
'SELECT actual_amount FROM monthly_bill_state WHERE bill_id = ? AND year = ? AND month = ?',
|
|
|
|
|
|
)
|
|
|
|
|
|
.get(billId, y, m);
|
2026-05-28 02:09:49 -05:00
|
|
|
|
|
|
|
|
|
|
if (mbs?.actual_amount != null) {
|
|
|
|
|
|
amounts.push(mbs.actual_amount);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const result = db
|
|
|
|
|
|
.prepare(
|
|
|
|
|
|
`
|
2026-05-28 02:09:49 -05:00
|
|
|
|
SELECT COALESCE(SUM(amount), 0) AS total
|
|
|
|
|
|
FROM payments
|
|
|
|
|
|
WHERE bill_id = ?
|
|
|
|
|
|
AND deleted_at IS NULL
|
2026-06-07 01:05:48 -05:00
|
|
|
|
AND ${accountingActiveSql()}
|
2026-05-28 02:09:49 -05:00
|
|
|
|
AND strftime('%Y', paid_date) = ?
|
|
|
|
|
|
AND strftime('%m', paid_date) = ?
|
2026-07-06 14:23:53 -05:00
|
|
|
|
`,
|
|
|
|
|
|
)
|
|
|
|
|
|
.get(billId, String(y), String(m).padStart(2, '0'));
|
2026-05-28 02:09:49 -05:00
|
|
|
|
|
|
|
|
|
|
if (result.total > 0) amounts.push(result.total);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
return medianSuggestion(amounts);
|
|
|
|
|
|
}
|
2026-05-28 02:09:49 -05:00
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
/**
|
|
|
|
|
|
* Batched form of computeAmountSuggestion for many bills at once: two queries
|
|
|
|
|
|
* total (monthly_bill_state + grouped payment sums) instead of up to 12 per
|
|
|
|
|
|
* bill. Returns a Map<billId, suggestion|null>. Behavior-identical to calling
|
|
|
|
|
|
* computeAmountSuggestion per bill (guarded by amountSuggestionService.test.js).
|
|
|
|
|
|
*/
|
2026-07-06 14:23:53 -05:00
|
|
|
|
function computeAmountSuggestionsBatch(
|
|
|
|
|
|
db: Db,
|
|
|
|
|
|
billIds: number[],
|
|
|
|
|
|
year: number,
|
|
|
|
|
|
month: number,
|
|
|
|
|
|
): Map<number, AmountSuggestion | null> {
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
const result = new Map<number, AmountSuggestion | null>();
|
2026-07-03 18:25:55 -05:00
|
|
|
|
if (!billIds || billIds.length === 0) return result;
|
2026-05-28 02:09:49 -05:00
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
const months = priorMonths(year, month, 6);
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const monthKeys = new Set(months.map((mm) => mm.key));
|
2026-07-03 18:25:55 -05:00
|
|
|
|
const minKey = months[months.length - 1].key; // earliest (month − 6)
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const maxKey = months[0].key; // latest (month − 1)
|
2026-07-03 18:25:55 -05:00
|
|
|
|
// Broad window that fully spans the 6 months; the monthKeys filter below is
|
|
|
|
|
|
// the exact gate, so a '-01'…'-31' string window is safe for ISO dates.
|
|
|
|
|
|
const windowStart = `${minKey}-01`;
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const windowEnd = `${maxKey}-31`;
|
2026-07-03 18:25:55 -05:00
|
|
|
|
|
|
|
|
|
|
const placeholders = billIds.map(() => '?').join(',');
|
|
|
|
|
|
|
|
|
|
|
|
// User-corrected monthly amounts.
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
const mbsMap = new Map<number, Record<string, number>>(); // billId → { 'YYYY-MM': actual_amount }
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const mbsRows = db
|
|
|
|
|
|
.prepare(
|
|
|
|
|
|
`
|
2026-07-03 18:25:55 -05:00
|
|
|
|
SELECT bill_id, year, month, actual_amount
|
|
|
|
|
|
FROM monthly_bill_state
|
|
|
|
|
|
WHERE bill_id IN (${placeholders})
|
2026-07-06 14:23:53 -05:00
|
|
|
|
`,
|
|
|
|
|
|
)
|
|
|
|
|
|
.all(...billIds);
|
2026-07-03 18:25:55 -05:00
|
|
|
|
for (const r of mbsRows) {
|
|
|
|
|
|
if (r.actual_amount == null) continue;
|
|
|
|
|
|
const key = `${r.year}-${String(r.month).padStart(2, '0')}`;
|
|
|
|
|
|
if (!monthKeys.has(key)) continue;
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
let bucket = mbsMap.get(r.bill_id);
|
2026-07-06 14:23:53 -05:00
|
|
|
|
if (!bucket) {
|
|
|
|
|
|
bucket = {};
|
|
|
|
|
|
mbsMap.set(r.bill_id, bucket);
|
|
|
|
|
|
}
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
bucket[key] = r.actual_amount;
|
2026-07-03 18:25:55 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Payment sums grouped by bill + month.
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
const payMap = new Map<number, Record<string, number>>(); // billId → { 'YYYY-MM': total }
|
2026-07-06 14:23:53 -05:00
|
|
|
|
const payRows = db
|
|
|
|
|
|
.prepare(
|
|
|
|
|
|
`
|
2026-07-03 18:25:55 -05:00
|
|
|
|
SELECT bill_id, strftime('%Y-%m', paid_date) AS ym, COALESCE(SUM(amount), 0) AS total
|
|
|
|
|
|
FROM payments
|
|
|
|
|
|
WHERE bill_id IN (${placeholders})
|
|
|
|
|
|
AND deleted_at IS NULL
|
|
|
|
|
|
AND ${accountingActiveSql()}
|
|
|
|
|
|
AND paid_date BETWEEN ? AND ?
|
|
|
|
|
|
GROUP BY bill_id, ym
|
2026-07-06 14:23:53 -05:00
|
|
|
|
`,
|
|
|
|
|
|
)
|
|
|
|
|
|
.all(...billIds, windowStart, windowEnd);
|
2026-07-03 18:25:55 -05:00
|
|
|
|
for (const r of payRows) {
|
|
|
|
|
|
if (!monthKeys.has(r.ym)) continue;
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
let bucket = payMap.get(r.bill_id);
|
2026-07-06 14:23:53 -05:00
|
|
|
|
if (!bucket) {
|
|
|
|
|
|
bucket = {};
|
|
|
|
|
|
payMap.set(r.bill_id, bucket);
|
|
|
|
|
|
}
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
bucket[r.ym] = r.total;
|
2026-07-03 18:25:55 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const billId of billIds) {
|
refactor(server): migrate 10 services to TypeScript (.cts)
Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 10:35:29 -05:00
|
|
|
|
const amounts: number[] = [];
|
2026-07-03 18:25:55 -05:00
|
|
|
|
const mbsFor = mbsMap.get(billId) || {};
|
|
|
|
|
|
const payFor = payMap.get(billId) || {};
|
|
|
|
|
|
for (const { key } of months) {
|
2026-07-06 14:23:53 -05:00
|
|
|
|
if (mbsFor[key] != null) {
|
|
|
|
|
|
amounts.push(mbsFor[key]);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2026-07-03 18:25:55 -05:00
|
|
|
|
const total = payFor[key] || 0;
|
|
|
|
|
|
if (total > 0) amounts.push(total);
|
|
|
|
|
|
}
|
|
|
|
|
|
result.set(billId, medianSuggestion(amounts));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
2026-05-28 02:09:49 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-03 18:25:55 -05:00
|
|
|
|
module.exports = { computeAmountSuggestion, computeAmountSuggestionsBatch };
|