Files
PowderCoatingLogix/docs/ACCOUNTING_DEPLOY_VERIFICATION.md
T
spouliot 8b9a3dff41 Add accounting deploy & verification checklist
Repeatable post-deploy (and periodic) check that proves the books are consistent
against real data: per company, Trial Balance debits==credits, Balance Reconciliation
shows no drift, then Recalculate Balances and re-check. Includes the read-only
pre-deploy migration preview, the two pending migrations in order, account spot-checks
for the audit-touched accounts, and the inventory/sales-tax policy reminders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:42:32 -04:00

87 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Accounting Deploy & Verification Checklist
> Repeatable steps to run whenever accounting changes ship (and a good periodic health check).
> Goal: prove the books are internally consistent with **real data**, not just code review.
> Companions: `docs/ACCOUNTING_AUDIT.md` (findings/decisions), `docs/ACCOUNTING_LEDGER_REFACTOR.md` (future).
The decisive invariant: **a Trial Balance whose total debits == total credits, with no drift on the
Balance Reconciliation report, for every company.** If that holds, the ledger is sound by construction.
---
## 1. Pre-deploy (against the production DB, read-only)
Migrations are applied **manually** at deploy (the app does not auto-migrate). Two are pending from the
2026-06 audit; apply in this order:
1. `RenameDepositsAccountAddPayroll` (O1 — renames 2300 → "Customer Deposits", adds 2400 Payroll)
2. `FixGiftCertificateLiabilityAccount` (O5 — relabels mislabeled 2500 → GC Liability, adds 2900)
Both are non-destructive (no account Id / number / balance is changed; only relabels + additive inserts).
Preview exactly what they'll touch (read-only — swap account numbers as needed):
```sql
-- O1: 2300 rows that will be renamed (only those still named the default), and who gets a new 2400
SELECT CompanyId, AccountNumber, Name, CurrentBalance,
CASE WHEN Name = 'Payroll Liabilities' THEN 'WILL RENAME -> Customer Deposits' ELSE 'kept as-is' END AS Action
FROM Accounts WHERE AccountNumber = '2300' AND IsDeleted = 0 ORDER BY CompanyId;
-- O5: 2500 rows that will be relabeled (only those still named "Long-Term Loan")
SELECT CompanyId, AccountNumber, Name, CurrentBalance,
CASE WHEN Name = 'Long-Term Loan' THEN 'WILL RELABEL -> Gift Certificate Liability' ELSE 'kept as-is' END AS Action
FROM Accounts WHERE AccountNumber = '2500' AND IsDeleted = 0 ORDER BY CompanyId;
```
## 2. Deploy
1. Merge `dev``master`, trigger the Jenkins production job.
2. Apply the two migrations above (in order) to the production DB.
## 3. Post-deploy verification (per company — all of them)
Run for **every** company (there are ~7). Most is doable from the app UI under Reports / Finance.
- [ ] **Trial Balance** — open it. **Total Debits must equal Total Credits.** Any difference is a
one-sided posting and must be investigated before trusting other reports.
- [ ] **Balance Reconciliation report** (`/Reports/Reconciliation`) — every account's *stored* balance
should match the *recomputed* balance (no drift highlighted). Also confirm:
- AR control account == sum of customer balances (AR subledger).
- AP control account == sum of vendor balances (AP subledger).
- [ ] **Recalculate Balances**, then re-open the Trial Balance and Balance Reconciliation. This exercises
the recompute paths the audit fixed (`LedgerService`). After a recalc:
- Trial Balance still balances.
- Reconciliation shows no drift (stored now == recomputed by definition; the point is TB stays balanced
and the values look sane).
## 4. Spot-check the accounts the audit touched
For each company, glance at these on the Trial Balance / chart of accounts:
- [ ] **2300 Customer Deposits** — named correctly; balance == outstanding (un-applied) customer deposits.
- [ ] **2400 Payroll Liabilities** — exists (likely 0 unless payroll is tracked).
- [ ] **2500 Gift Certificate Liability** — named correctly; balance == outstanding GC value (issued redeemed voided).
- [ ] **2900 Long-Term Loan** — present where the old 2500 was relabeled.
- [ ] **4950 Sales Discounts / 4960 Sales Returns** — contra-revenue, show as debit-balance.
- [ ] **AR** — for any company that uses gift certificates or has written off an invoice, confirm AR is not
overstated (these were O7 / O8). Cross-check AR total against the AR Aging report.
## 5. If something is off
- A Trial Balance that doesn't balance → a posting hit only one side. Note the company + amount and check it
against the findings in `docs/ACCOUNTING_AUDIT.md` (the resolved O2/O6/O7/O8 patterns) before assuming a new bug.
- Drift on the Reconciliation report → run **Recalculate Balances**; if it persists, the recompute is missing a
posting type (same class as the audit findings).
- Do **not** treat a recalc as a fix for a real imbalance — it makes stored == recomputed, which can *hide* a
one-sided posting if only one engine is wrong. The Trial Balance balancing is the real test.
## 6. Policy reminders (from the audit)
- **Inventory = expensed at purchase (periodic).** Do **not** map an item's `CogsAccountId` + `InventoryAccountId`
(set only via CSV import) while also expensing powder at purchase — that double-counts COGS. Keep those empty.
- Sales-tax remittance is capped at the outstanding 2200 balance (O4) — you cannot over-remit.
## When to repeat
- After any accounting feature change or import.
- As a periodic health check (e.g. monthly), run Section 3 — it's cheap and catches drift early.