-
DevPilot authored
feat(accounting): implement accountant's spec sheet — split fees, branch policy, government withholding Sheraton's accountant handed over a 274-row spec for tomorrow's meeting. Most of it was already correct (payroll, rentals, academies); this closes the concrete gaps and builds the tools for the parts that are policy decisions, not code. ADDITION-FEE REVENUE SPLIT (spec rows 72-88) The spec asks for the fee split "according to the ratio of the revenue" without ever giving a ratio — but the ratio already existed: ChildFeeCalculator/SpouseFeeCalculator compute a membership-value component, a form-fee component and an annual-subscription component on every addition. It just wasn't persisted past the display breakdown, so by payment time nothing to split by. Now stored (fee_component_* columns) and posted as three separate credits instead of one lump "dependant addition" line, with a safety check that skips the split (falls through unchanged) if the collected amount doesn't match the stored components exactly. MEMBERSHIP-FORM STAMP FEE (row 12) BillingService's own price breakdown already reads "form fee: 500 — stamp: 5" — the 505 EGP was never wrong, accounting just credited all of it to form revenue. Now splits the 5 EGP to the government stamp liability that already existed in the chart, unused (23082103 طابع الشهداء). Only fires where a branch has it configured — every other branch posts exactly as before. BRANCH FEE SETTINGS — a real tool, not a guess The spec argues with itself about several fees: "add this at Sheraton" against "cancel it everywhere" in consecutive lines, "each branch has its own card-commission rate" with a rate given for exactly one branch. /accounting/branch-fees is where that gets decided per branch or once for all of them, with a one-click "generalize to every branch" action — covers the stamp fee, cheque clearing fee, bounced-cheque fee, and a tiered card commission (threshold + rate + whole-vs-excess basis, with a live preview). Seeded active for Sheraton with the exact figures the spec gives; every other branch starts with nothing configured. CARD COMMISSION — posted as an expense, not left in the bank figure Implemented as a small adjusting entry after the main collection posts (Dr commission expense / Cr the same card account, reclassifying part of what was already debited) rather than rewritten into ~30 payment types' posting logic. Verified: 50,000 EGP visa payment above a 10,000 threshold at 2% posts exactly 800.00, non-visa payments are untouched, replay does not double-post. GOVERNMENT WITHHOLDING ON EXPENSES (rows 223-264) Ordinary stamp duty, additional stamp duty, commercial-profits withholding — deducted at source from every vendor invoice, reusing liability accounts the chart already had unused (23081202-23081204). Rates are not guessed: Egyptian withholding schedules are progressive law, not a percentage this migration could safely invent, so it ships at 0% and inactive until finance sets real rates on the same settings screen. Accounts payable now records the NET amount owed after withholding, which is what the club actually pays. CASH DISBURSEMENT BANNED FOR EXPENSES (rows 190-191) "As a government institution, cash disbursement is forbidden — every expense by cheque." Enforced once, at VendorPaymentService::createPayment, with a system_config kill switch for the day this genuinely needs an exception (logged as a deliberate override, not a silent bypass). NOTES PAYABLE — cheques now a liability until the bank clears them onVendorPaymentCompleted was crediting Bank directly the moment a cheque was issued, before the bank had paid anything. Now credits أوراق دفع (notes payable) instead, and /accounting/notes-payable is the monthly reconciliation the spec asks for at rows 267-269: pick the cheques the bank statement confirms cleared, post one closing entry. Zero live vendor payments existed, so this changes no historical data. Verified end-to-end against a scratch copy of production: every scenario checked exactly against hand-computed expected values (not just "it posted something") — split amounts, commission arithmetic, withholding math, net payable — trial balance nets to 0.00, zero unbalanced entries, zero postings to header accounts, every path idempotent under replay. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
d74b0ee5
| Name |
Last commit
|
Last update |
|---|---|---|
| .. | ||
| migrations | ||
| seeds | ||
| schema.sql |