fix(accounting): verify and fix Zarrin driver on real v228 install

Tested 20/20 on the owner's live Zarrin v228 (870 accounts, 656 items):

Reads fixed:
- listKarSakhte: now pages by 100 via pageNum (was returning only first 100 of 656)
- goroohSakhte: HTTP 400 with a valid body is now accepted (was treated as missing)
- parvande «مانده از قبل» row is not a balance; skip it and anchor the running
  balance on the live listMandeHesabha balance, walked back through movements
- infogardeshsakhte: hand-printed JSON repaired, timeout raised to 90s
- document delete: now searches all ledger pages, not just the first one
- listhesabha names are «first * last»; the «*» is now stripped
- keep-alive ECONNRESET: a socket hang-up on a reused connection is retried once
  on a fresh connection (server closes idle connections)

Writes fixed (test account 953 «تست اپ گلدبانک»):
- temporary flag: set from shomareSanad («موقت»), not noeFactor
- noeFactor «فاکتور موقت» also flags a document left open in Zarrin's own UI

New: test script apps/api/scripts/test-accounting-zarrin.ts (13 read + 7 write checks)
Docs: §13 added to ACCOUNTING-INTEGRATION-PLAN.md; ACC-01 in ISSUES.md updated
New: docs/FRESH-SERVER-DEPLOY-AUDIT.md (fresh-server deploy checklist)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-10-12 15:23:24 +03:30
co-authored by Claude Sonnet 4.6
parent 9fc0886a57
commit 8b74c85a2a
7 changed files with 574 additions and 50 deletions
+1 -1
View File
@@ -184,7 +184,7 @@ Severity: `Critical` (money loss / security / data loss) · `High` · `Medium`
| ID | Severity | Where | Description | Evidence | Suggested fix |
|---|---|---|---|---|---|
| **ACC-01** | Medium (unverified) | TGT `accounting-sync/providers/zarrin.provider.ts` | The Zarrin driver follows the published docs only — there is no Zarrin installation to test on. Open points: which sign of `listMandeHesabha` means "owes" (a setting, default negative), whether stones belong in `mablagh` or `mablaghSang` on `foroushSakhte` (sent in `mablagh`), and the exact response envelopes. | Owner: «نه، فعلاً نداریم» (no test install). Unit tests use the docs' sample outputs. | Before real use: a trial on temporary documents on a real install (owner's decision 11), check one balance and one document against the Zarrin UI. |
| **ACC-01** | Medium (unverified) | TGT `accounting-sync/providers/zarrin.provider.ts` | The Zarrin driver follows the published docs only — there is no Zarrin installation to test on. Open points: which sign of `listMandeHesabha` means "owes" (a setting, default negative), whether stones belong in `mablagh` or `mablaghSang` on `foroushSakhte` (sent in `mablagh`), and the exact response envelopes. | Owner: «نه، فعلاً نداریم» (no test install). Unit tests use the docs' sample outputs. | Before real use: a trial on temporary documents on a real install (owner's decision 11), check one balance and one document against the Zarrin UI. **Update 2026-10-12 — reads verified on the owner's install (v228, 870 accounts, 656 items):** negative balance = owes (default is right); a «فاکتور موقت» moves the balance at once (unlike Tahesab, ACC-02); fixed: `listKarSakhte` pages by 100 via `pageNum` (only 100 of 656 were read), `goroohSakhte` answers HTTP 400 with a good body (was treated as missing), the statement now skips «مانده از قبل» and is anchored on the live balance (its last row now equals Zarrin's balance; ranges agree on shared rows), temporary rows flagged, `infogardeshsakhte`'s hand-printed JSON repaired (+90 s timeout; Zarrin itself sometimes answers 500), document delete searches every ledger page, and a request on a kept-alive connection the server already closed is retried once on a fresh one ("socket hang up"). **Writes verified 2026-10-12** on owner-approved test account 953 «تست اپ گلدبانک» (09990001111, group متفرقه — Zarrin has no API to delete it, so it stays): addAccount, searchAccount finds it, edithesab keeps the group; foroushSakhte (bonak, 2 lines × 1 g, 10 %, movaghat=1) moved the balance by exactly 2.2 g = our acceptance rule, stock fell 1 g per item; hazfRadifSanad (kol=1) removed every row, balance and stock back to start. Fixed from that test: a movaghat=1 document is marked in `shomareSanad` («موقت»), not `noeFactor`; listhesabha names are «first * last» (all 873) — the «*» is now dropped. addFelezsakhteModel NOT tested (owner: no permanent test item). Security: the install is plain http on the internet with token `123456`. |
| **ACC-02** | Low (by design) | TGT D27 | Order documents are sent **temporary** (owner ruling), and a temporary Tahesab document does **not** move the balance until the accountant finalises it. Until then the balance the customer sees from the accounting software does not include those orders. | Measured on the Tahesab test server: balance delta 0 for a temporary `VKHKar`, −Vazn×Ayar/750 once final. | Accountant finalises documents promptly; the report marks temporary rows «موقت — هنوز در مانده اثر ندارد». |
| **ACC-03** | ~~**High**~~ **FIXED 2026-10-08 (owner-approved)** — `LedgerService.syncOrderDebt`: on every status change the order's ORDER_STOCK entries are brought to what legacy's recomputed `sts > 4` gives (full weight + rial while DELIVERED_TO_AGENT/CUSTOMER, else 0), posting only the difference as a confirmed DEBIT/CREDIT. Also fixes: straight-to-DELIVERED_TO_CUSTOMER owed nothing; rollback/cancel left the debt. Removing the «تحویل به نماینده» status is allowed again, as in legacy. Existing data: 0 orders out of line in dev and the imported copy. | TGT `orders/orders.service.ts` `updateStatus()` | The debt guard is `DELIVERED_TO_AGENT && !order.deliveredAt`, but `deliveredAt` is only set at `DELIVERED_TO_CUSTOMER`. An order moved into DELIVERED_TO_AGENT a second time (e.g. PREPARING → DELIVERED_TO_AGENT again via «تغییر وضعیت») posts the gold and rial debt **twice**. | Read at `orders.service.ts:135-160`. The new accounting hook is not affected (it dedupes on the existing document row). | Guard on an existing `ORDER_STOCK` ledger entry for the order instead of `deliveredAt`; needs owner approval (PROTECTED area). |
| **ACC-04** | Low (pre-existing) | TGT `src/prisma/migrate.ts` | On a completely empty database `runMigrations` fails: `0002_admin_schema.sql` sorts before `20260910113720_first` and alters tables that do not exist yet. Existing databases are unaffected. | Reproduced while preparing the D27 throwaway test database (`relation "City" does not exist`). | Rename to sort after `first`, with a `LEGACY_NAME_ALIASES` entry so applied databases do not re-run it. |