fix(reports): count reversed entries in bank/supplier/AR reconciliation (#734)
A reversed (storno-corrected) journal entry must be summed together with
its storno + correction, exactly as the trial balance and balance sheet
already do (.in('status', ['posted','reversed'])). The reconciliation
paths used posted-only and manufactured phantom differences.
- bank-reconciliation getReconciliationStatus: gl_1930_balance now counts
posted+reversed (so it equals the balansräkning for the account). Dropped
the correction_adjustment subtraction and the reversed-linked-tx drop — a
corrected/amount-corrected bank receipt now reconciles. The prior model
broke once correctEntry began re-pointing the bank transaction to the live
correction (the two changes were mutually inconsistent and produced a
difference equal to the corrected amount).
- supplier-reconciliation (2440) and ar-reconciliation (1510/1513): same
posted -> posted+reversed fix. Removes the false "Ej avstämd" gap a fully
paid, fully corrected company shows — the books net to 0 over posted+reversed
while a posted-only query double-counted the payment legs.
Also in this change:
- MCP gnubok_get_reconciliation_status: add account_number param (was hardcoded
to 1930; the lib already supported per-account reconciliation).
- counterparty-templates normalizeCounterpartyName: strip trailing month /
personal-initials tokens so "ngrok JW" / "Ngrok Mars" learn as one merchant.
- pending-operation reject 409 (route + MCP tool): clarify a resolved op was
approved explicitly (no auto-commit path exists) instead of a bare
"already committed".
- create_voucher: normalize description with String().trim() for consistency
with line_description.
- migration 20260625120000: backfill stripped diacritics on ~830 companies'
seeded chart-of-accounts names (Foretagskonto -> Företagskonto, etc.); the
seed function was fixed for new companies in 20260516130000 but never
backfilled. UPDATE-only and idempotent. Already applied to production.
Tests: 899 passing across the touched suites; lint + typecheck clean.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fa4daf6f98
commit
e5f1d7a916
@@ -73,8 +73,21 @@ export async function POST(
|
||||
}
|
||||
|
||||
if (op.status !== 'pending') {
|
||||
// There is no auto-commit path (removed in 20260505190027), so a non-pending
|
||||
// status here means the op was resolved explicitly — almost always the user
|
||||
// pressed Godkänn in the /pending (Att göra) UI in parallel, or another
|
||||
// client already rejected it. Spell that out so an agent doesn't read the
|
||||
// generic 409 as "the system committed it behind my back".
|
||||
const explained =
|
||||
op.status === 'rejected'
|
||||
? 'Operation already rejected.'
|
||||
: op.status === 'expired'
|
||||
? 'Operation already expired and can no longer be rejected.'
|
||||
: `Operation already ${op.status} — it was approved explicitly (most likely via the ` +
|
||||
'Att göra / pending UI in parallel), not auto-committed. It can no longer be rejected; ' +
|
||||
'reverse or correct the resulting verifikat instead.'
|
||||
return NextResponse.json(
|
||||
{ error: `Operation already ${op.status}` },
|
||||
{ error: explained, status: op.status },
|
||||
{ status: 409 }
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user