B-13 · Complete reconciliation & generate report
SOP:
SOP_AI_Bookkeeping_Automation.md§5.4 (Reconciliation Completion and Reporting)Actors: Bookkeeper. Pre-state: EveryUnreconciledItemfor the run is inRESOLVED. EveryReconciliationMatchis confirmed. Post-state:ReconciliationRun.status = COMPLETE. CSV + PDF reconciliation report stored as aFileand linked viareportFileId. Email summary dispatched toreviewerEmail.
0. Prerequisites
1. Steps
1.1 Verify completeness
GET /ops/bookkeeping/reconciliations/<runId>Response includes counters:
{
"status": "AWAITING_CLIENT",
"totals": {
"matched": 3,
"unreconciled": { "PENDING": 0, "CLIENT_RESPONDED": 0, "RESOLVED": 3 }
}
}If any non-RESOLVED items remain, the Complete button is disabled.
1.2 Click Complete
Web: /dashboard/bookkeeping/reconciliations/<runId> → Complete reconciliation.
POST /ops/bookkeeping/reconciliations/<runId>/completeServer:
- Re-checks every match is confirmed and every unreconciled item is
RESOLVED. Otherwise 400 with the offending ids. - Transitions
status = COMPLETE, stampscompletedAt. - Enqueues
bookkeeping.generate-reconciliation-report.
1.3 Worker generates the report
bookkeeping.generate-reconciliation-report handler:
- Loads the run + statement + every match + every unreconciled item.
- Renders a CSV (one row per bank transaction with match status, journal entry reference, amount) and a PDF summary:
- Opening balance per statement.
- Closing balance per statement.
- List of matched transactions with journal entry references.
- List of resolved-via-client items (uploaded vs no-supporting).
- Uploads both to S3 at
<clientCode>/bookkeeping/<period>/reconciliation/v<n>/report.{csv,pdf}. - Persists
Filerows; links the PDF viaReconciliationRun.reportFileId. - Sends an email to
bookkeepingConfig.reviewerEmailwith the report attached + summary text. - Writes
bookkeeping.reconciliation.report_generatedaudit event.
1.4 Download the report
/dashboard/bookkeeping/reconciliations/<runId> → Download report (CSV) and Download report (PDF) buttons. Both resolve presigned S3 URLs.
2. Verification
Database
SELECT status, completed_at, report_file_id
FROM reconciliation_runs WHERE id = '<runId>';
-- COMPLETE, completed_at set, report_file_id not nullS3 / MinIO
<clientCode>/bookkeeping/<period>/reconciliation/v1/report.pdf and .csv.
Mailpit
A summary email with attachments to reviewerEmail. Subject: Reconciliation report — {clientName} {period}.
Audit log
bookkeeping.reconciliation.completed runId=<id>
bookkeeping.reconciliation.report_generated runId=<id> fileId=<id>3. Negative & edge cases
- Open items remain → 400 with the offending unreconciled item ids and / or proposed match ids.
- Run already
COMPLETE→ 409"Run is already complete." - Report render failure — handler logs and rethrows; pg-boss retries. The run stays
COMPLETE(it transitioned before the render kicked off); the report can be re-rendered manually viaPOST /ops/bookkeeping/reconciliations/<runId>/regenerate-report. - No approval round / sign-off — bookkeeping does not yet have a client-side approval round equivalent to payroll. The reviewer's POST is terminal. If the engagement requires a second client sign-off, that's out of scope for the MVP — track via the integration plan.
Next
The run is closed. Future statements for the same client + bank account follow the same flow. To exercise the annual variant (large bulk + multiple statements at once), see B-14 · Annual bookkeeping.