mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Movement of Equity GL-consistent; wire reconciliation checks R3/R5 (+R6/R9)
The Movement of Equity derived net income from sub-ledgers (calcNetIncome over invoices/expenses/bills), while the P&L and Balance Sheet use the GL. With any direct bank-categorized income/expense the two disagreed — Ashley Manor's SCE was off from the Balance Sheet equity by 9,257.44. Rebuild Movement of Equity from the GL (current-year earnings + GL equity balances) so all three statements tie by construction. Complete the §9 reconciliation matrix: R3 (P&L net income == raw-GL period net income — guards the P&L builder) and R5 (Movement of Equity ending == Balance Sheet total equity) are now computed by cross-checking the report builders against the raw GL; checks render in numeric order. R6 (GL == TB/BS, satisfied by construction) and R9 (direct vs indirect CFO, only indirect built) shown as N/A for matrix completeness. Adds 5 reconcile unit tests (12 total). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,19 @@ export interface ReconcileInput {
|
||||
* Defaults to true.
|
||||
*/
|
||||
arApApplicable?: boolean;
|
||||
/**
|
||||
* Net income for the period as produced by the app's P&L builder. R3 cross-checks
|
||||
* it against the raw-GL period net income computed here, catching a P&L
|
||||
* classification/grouping bug. Omitted → R3 is skipped.
|
||||
*/
|
||||
reportPLNetIncome?: number;
|
||||
/**
|
||||
* Ending equity from the Movement-of-Equity builder and total equity from the
|
||||
* Balance Sheet builder. R5 cross-checks that the two statements agree.
|
||||
* Both omitted → R5 is skipped.
|
||||
*/
|
||||
sceEndingEquity?: number;
|
||||
bsTotalEquity?: number;
|
||||
}
|
||||
|
||||
export interface RecCheck { id: string; label: string; residual: number; pass: boolean }
|
||||
@@ -90,6 +103,14 @@ export function reconcile(input: ReconcileInput): RecCheck[] {
|
||||
{ id: "R2", label: "Balance Sheet — Assets = Liabilities + Equity (incl. net income)", residual: assets - (liab + equity + netIncomeCum) },
|
||||
{ id: "R4", label: "Cash Flow — CFO+CFI+CFF = change in cash", residual: (periodNI + nonCashImpact) - deltaCash },
|
||||
];
|
||||
// R3: the P&L builder's net income must equal the raw-GL period net income.
|
||||
if (input.reportPLNetIncome !== undefined) {
|
||||
checks.push({ id: "R3", label: "P&L net income = period net income from the GL", residual: input.reportPLNetIncome - periodNI });
|
||||
}
|
||||
// R5: the Movement-of-Equity ending equity must equal the Balance Sheet total equity.
|
||||
if (input.sceEndingEquity !== undefined && input.bsTotalEquity !== undefined) {
|
||||
checks.push({ id: "R5", label: "Movement of Equity ending = Balance Sheet total equity", residual: input.sceEndingEquity - input.bsTotalEquity });
|
||||
}
|
||||
// R7/R8 (sub-ledger vs GL control) only apply to platform-managed companies.
|
||||
if (input.arApApplicable !== false) {
|
||||
checks.push(
|
||||
@@ -97,5 +118,6 @@ export function reconcile(input: ReconcileInput): RecCheck[] {
|
||||
{ id: "R8", label: "A/P = open bill balances (§1.5)", residual: apControl - input.openBills },
|
||||
);
|
||||
}
|
||||
checks.sort((a, b) => Number(a.id.slice(1)) - Number(b.id.slice(1)));
|
||||
return checks.map((c) => ({ ...c, pass: near(c.residual) }));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user