jaz-clio 5.65.0 → 5.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/skills/api/SKILL.md +5 -5
- package/assets/skills/api/references/errors.md +2 -2
- package/assets/skills/api/references/search-enums.md +2 -2
- package/assets/skills/cli/SKILL.md +1 -1
- package/assets/skills/cli/references/error-recovery.md +1 -1
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/jaz-kit/SKILL.md +1 -1
- package/assets/skills/jaz-pseudo-sql/SKILL.md +1 -1
- package/assets/skills/jaz-pseudo-sql/references/error-catalog.md +1 -1
- package/assets/skills/jobs/SKILL.md +1 -1
- package/assets/skills/jobs/references/audit-prep.md +30 -30
- package/assets/skills/jobs/references/bank-recon.md +18 -21
- package/assets/skills/jobs/references/building-blocks.md +7 -7
- package/assets/skills/jobs/references/credit-control.md +21 -22
- package/assets/skills/jobs/references/document-collection.md +9 -11
- package/assets/skills/jobs/references/fa-review.md +18 -19
- package/assets/skills/jobs/references/gst-vat-filing.md +5 -5
- package/assets/skills/jobs/references/month-end-close.md +23 -23
- package/assets/skills/jobs/references/payment-run.md +22 -24
- package/assets/skills/jobs/references/quarter-end-close.md +14 -14
- package/assets/skills/jobs/references/supplier-recon.md +7 -7
- package/assets/skills/jobs/references/year-end-close.md +13 -18
- package/assets/skills/transaction-recipes/SKILL.md +3 -3
- package/assets/skills/transaction-recipes/references/accrued-expenses.md +8 -13
- package/assets/skills/transaction-recipes/references/asset-disposal.md +14 -21
- package/assets/skills/transaction-recipes/references/bad-debt-provision.md +22 -23
- package/assets/skills/transaction-recipes/references/bank-loan.md +7 -13
- package/assets/skills/transaction-recipes/references/building-blocks.md +16 -15
- package/assets/skills/transaction-recipes/references/capital-wip.md +30 -25
- package/assets/skills/transaction-recipes/references/declining-balance.md +4 -8
- package/assets/skills/transaction-recipes/references/deferred-revenue.md +6 -11
- package/assets/skills/transaction-recipes/references/dividend.md +9 -16
- package/assets/skills/transaction-recipes/references/employee-accruals.md +10 -19
- package/assets/skills/transaction-recipes/references/fixed-deposit.md +5 -11
- package/assets/skills/transaction-recipes/references/fx-revaluation.md +10 -9
- package/assets/skills/transaction-recipes/references/hire-purchase.md +15 -10
- package/assets/skills/transaction-recipes/references/ifrs16-lease.md +25 -27
- package/assets/skills/transaction-recipes/references/intercompany.md +30 -34
- package/assets/skills/transaction-recipes/references/prepaid-amortization.md +6 -11
- package/assets/skills/transaction-recipes/references/provisions.md +5 -12
- package/cli.mjs +492 -492
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-api
|
|
3
|
-
version: 5.
|
|
3
|
+
version: 5.66.0
|
|
4
4
|
description: >-
|
|
5
5
|
Use this skill whenever you call, debug, or review code that touches the Jaz
|
|
6
6
|
REST API. Covers field names, response shapes, 159 production gotchas, error
|
|
@@ -206,7 +206,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
|
|
|
206
206
|
|
|
207
207
|
### Response Shape Gotchas
|
|
208
208
|
66. **Contact boolean fields are `customer`/`supplier`** — NOT `isCustomer`/`isSupplier`. These are plain booleans on the contact object: `{ "customer": true, "supplier": false }`. Using `isCustomer` or `isSupplier` in code will be `undefined`.
|
|
209
|
-
67. **Finalized statuses differ by resource type** — NOT `"FINALIZED"`, `"FINAL"`, or `"POSTED"`. Journals → `"ACTIVE"` (journals have no approval state — their lifecycle is `ACTIVE | VOID | DRAFT`; live-verified 2026-08-03). Invoices/Bills → `"UNPAID"` (progresses to `"
|
|
209
|
+
67. **Finalized statuses differ by resource type** — NOT `"FINALIZED"`, `"FINAL"`, or `"POSTED"`. Journals → `"ACTIVE"` (journals have no approval state — their lifecycle is `ACTIVE | VOID | DRAFT`; live-verified 2026-08-03). Invoices/Bills → `"UNPAID"` (progresses to `"PARTIALLY_PAID"`, `"PAID"`). `OVERDUE` is not a status (a list with it returns 422 and a search matches nothing), so find overdue documents with `status in [UNPAID, PARTIALLY_PAID]` plus `dueDate lt <today in the organization's timezone>`. Customer/Supplier Credit Notes → `"UNAPPLIED"` (progresses to `"PARTIALLY_APPLIED"`, `"APPLIED"`). All types support `"DRAFT"` and `"VOID"` (not `"VOIDED"`). When creating with `saveAsDraft: false`, the response status matches the type's finalized status.
|
|
210
210
|
68. **Create/pay responses are minimal by default** — POST create endpoints (invoices, bills, journals, contacts, payments) return only `{ resourceId: "..." }` (plus a few metadata fields). They do NOT return the full entity. To verify field values after creation, do a subsequent `GET /:type/:resourceId`. **MCP tool shortcut:** `create_invoice` / `create_bill` / `create_journal` / `create_contact` / `create_item` accept `returnFullEntity: true` — the executor performs the GET server-side and returns the full entity inline, saving a turn. The raw REST `POST` is still minimal-only; only the MCP tools collapse the round trip. **If the post-create GET fails** (transient 5xx, network blip), the tool returns the minimal create envelope augmented with `_hydration: { status: 'failed', resourceId, message }` — the write committed; the agent should retry only the `get_*` call, NEVER the create (would duplicate the document). **`_fx` on transaction creates:** invoice/bill/credit-note create results may carry a sibling `_fx` field, e.g. `FX: 1 SGD (your base) = 0.74 USD (applied rate for 2026-04-03)` — the exchange rate the record was ACTUALLY created with. Relay that line to the user verbatim; it matters most when the caller supplied no rate (the organization rate was applied silently, and a rate stored the wrong way round reads as an obviously absurd number the user can catch on sight).
|
|
211
211
|
69. **No `amountDue` field** — Invoices and bills do NOT have an `amountDue` field. To check if a transaction is fully paid, inspect the `paymentRecords` array: if `paymentRecords.length > 0`, payments exist. Compare `totalAmount` with the sum of `paymentRecords[].transactionAmount` to determine remaining balance.
|
|
212
212
|
70. **Response dates include time component** — Even though request dates are `YYYY-MM-DD`, response dates are epoch milliseconds (see Rule 52). When comparing dates from responses, always convert with `new Date(epochMs).toISOString().slice(0, 10)` — never string-match against the raw epoch value. Remember: business dates are org-timezone (see Rule 52).
|
|
@@ -351,7 +351,7 @@ Bills, invoices, and credit notes share identical mandatory field specs. Adding
|
|
|
351
351
|
103. **Journal entries must balance** — Sum of all DEBIT amounts must exactly equal sum of all CREDIT amounts. Unbalanced journals are rejected with 422. Agent tools pre-flight check this client-side before hitting the API.
|
|
352
352
|
|
|
353
353
|
### Transaction References
|
|
354
|
-
104. **References must be unique per org — NEVER invent one** —
|
|
354
|
+
104. **References must be unique per org — NEVER invent one** — On invoices, customer credit notes, quotes and orders a duplicate `reference` causes 422 `Sale Reference already exists`. Bills, supplier credit notes and manual journals accept a duplicate silently, so both documents keep the same number and nobody is told: search by reference before creating one again after an unconfirmed result. Ask whose number it is. **Purchase side (bills, supplier credit notes): use the SUPPLIER'S own document number**, read off the document; only if it genuinely has none, set `autoReference: true`. **Everything we issue (invoices, customer credit notes, quotes, sale orders, purchase requests, purchase orders, journals, expense claims): set `autoReference: true`** to take the next number from the organization's own series, or call `get_next_reference` to preview it first. Never a timestamp, never a guess, never a pattern inferred from other documents. This covers the business transaction families only; payments, cash entries, transfers, employee payouts, scheduled invoices, scheduled bills, scheduled journals and subscriptions have no series here and keep their own references. The scheduled bodies additionally REQUIRE a literal reference: they mint per occurrence upstream, so `autoReference` is rejected there even though the published schema shows the field. Sending both `reference` and `autoReference` is not an error here: the client resolves the number before the request and your explicit `reference` wins, costing one wasted series read. Send one. The assigned number always carries today's date even on a back-dated document, and reading the series does not reserve it.
|
|
355
355
|
|
|
356
356
|
### Currency Rates
|
|
357
357
|
105. **`add_currency_rate` for new rates, `update_currency_rate` only for editing existing records** — When a user says "update the rate" or "set the rate", use `add_currency_rate` (POST — creates a new rate entry for a date). Only use `update_currency_rate` (PUT) when explicitly modifying an existing rate record by its resourceId.
|
|
@@ -492,9 +492,9 @@ Bills, invoices, and credit notes share identical mandatory field specs. Adding
|
|
|
492
492
|
|
|
493
493
|
155. **Pseudo-SQL schema is canonical — call `get_pseudo_sql_schema` before any query.** The response returns the live curated catalog (tables / columns / joins / functions) PLUS the canonical `jaz-pseudo-sql.md` skill body in `agentSkillsDoc.content`. Drop the `.md` body into context as the syntax-rules source; treat `tables[] / joins[] / functions[]` as the column-list source. **Cache contract:** the `version` field is a stable 16-char hex hash; within a session, cache by version and don't re-call unless you have reason to believe the schema changed (e.g. a fresh backend deploy mid-session). Don't re-fetch on a wall-clock timer (upstream is `private, no-cache, must-revalidate`). A static curated-schema snapshot used to ship with the `jaz-pseudo-sql` skill before v5.6.0; it was dropped because it was structurally guaranteed to drift. Never write a query from a memorized column list.
|
|
494
494
|
|
|
495
|
-
156. **v1 capsule recipes are single-currency — `ERR_RECIPE_ACCOUNT_CURRENCY_MISMATCH`.** The recipe `currency` field, every `*AccountResourceId` account's `currencyCode`, and the base transaction's `currencyCode` ALL MUST match. Preview returns 422 `ERR_RECIPE_ACCOUNT_CURRENCY_MISMATCH` with a concrete message (e.g. "account X is denominated in USD but the recipe currency is SGD"). **Trigger mutation silently nulls `capsuleRecipeJob`** (Rule 143). Practical recipe: never hardcode `currency`; derive from `
|
|
495
|
+
156. **v1 capsule recipes are single-currency — `ERR_RECIPE_ACCOUNT_CURRENCY_MISMATCH`.** The recipe `currency` field, every `*AccountResourceId` account's `currencyCode`, and the base transaction's `currencyCode` ALL MUST match. Preview returns 422 `ERR_RECIPE_ACCOUNT_CURRENCY_MISMATCH` with a concrete message (e.g. "account X is denominated in USD but the recipe currency is SGD"). **Trigger mutation silently nulls `capsuleRecipeJob`** (Rule 143). Practical recipe: never hardcode `currency`; derive from the account's `currencyCode` (`search_accounts(filter: {resourceId: {eq: <prepaidAssetAccountResourceId>}})`) (or the base trx currency) and use the same value as the recipe input. The recipe descriptor's `currency.x-baseTrxBinding: "strict"` field marks this — when present, the value is bound to (and must equal) `trx.currencyCode` post-commit. Caught by smoke runs since v5.5.0 — tests 65/66 hardcoded `SGD` and silently nulled against a USD fire-test org for 20+ hours.
|
|
496
496
|
|
|
497
|
-
157. **Recipe input `*AccountResourceId` fields are account-class-locked — `x-accountClass` in inputSchema is authoritative.** Each `*AccountResourceId` slot on a recipe's input schema carries an `x-accountClass` constraint (`"Asset"`, `"Liability"`, `"Expense"`, `"Revenue"`, `"Equity"`). Passing an account whose class doesn't match the slot's `x-accountClass` is rejected post-commit and silently nulls `capsuleRecipeJob` (Rule 143). Schema location: `get_capsule_recipe(name).data.versions[0].inputSchema.properties.<fieldName>['x-accountClass']` — **note `versions[0].inputSchema`, NOT `inputSchema` at the top level**. Examples: PREPAID_AMORTIZATION needs `prepaidAssetAccountResourceId: Asset` + `expenseAccountResourceId: Expense`; DEFERRED_REVENUE needs `deferredRevenueAccountResourceId: Liability` + `revenueAccountResourceId: Revenue`; ACCRUAL_REVERSAL needs `expenseAccountResourceId: Expense` + `accruedLiabilityAccountResourceId: Liability`. Always pre-validate
|
|
497
|
+
157. **Recipe input `*AccountResourceId` fields are account-class-locked — `x-accountClass` in inputSchema is authoritative.** Each `*AccountResourceId` slot on a recipe's input schema carries an `x-accountClass` constraint (`"Asset"`, `"Liability"`, `"Expense"`, `"Revenue"`, `"Equity"`). Passing an account whose class doesn't match the slot's `x-accountClass` is rejected post-commit and silently nulls `capsuleRecipeJob` (Rule 143). Schema location: `get_capsule_recipe(name).data.versions[0].inputSchema.properties.<fieldName>['x-accountClass']` — **note `versions[0].inputSchema`, NOT `inputSchema` at the top level**. Examples: PREPAID_AMORTIZATION needs `prepaidAssetAccountResourceId: Asset` + `expenseAccountResourceId: Expense`; DEFERRED_REVENUE needs `deferredRevenueAccountResourceId: Liability` + `revenueAccountResourceId: Revenue`; ACCRUAL_REVERSAL needs `expenseAccountResourceId: Expense` + `accruedLiabilityAccountResourceId: Liability`. Always pre-validate the account's `accountClass` (`search_accounts(filter: {resourceId: {eq: <id>}})`) against the slot constraint, or just call `preview_capsule_recipe(recipeName, inputs)` to surface every class violation as a clean 422.
|
|
498
498
|
|
|
499
499
|
## Supporting Files
|
|
500
500
|
|
|
@@ -851,8 +851,8 @@ The same applies on update: `PUT /cash-in-entries/:id` with `saveAsDraft: true`
|
|
|
851
851
|
## Invoices / Bills
|
|
852
852
|
|
|
853
853
|
### "Sale Reference already exists" (422) — duplicate reference
|
|
854
|
-
**Cause**: Creating an invoice
|
|
855
|
-
**Fix**: Do not invent a number. For
|
|
854
|
+
**Cause**: Creating an invoice, customer credit note, quote or order with a `reference` that already exists in the org.
|
|
855
|
+
**Fix**: Do not invent a number. For anything the organization issues, set `autoReference: true` (or call `get_next_reference` first) to take the next number from its own series. Bills, supplier credit notes and manual journals never return this error: they accept a duplicate reference silently and book a second document, so search by reference before re-creating one after an uncertain result. For a bill or supplier credit note use the supplier's own document number.
|
|
856
856
|
|
|
857
857
|
---
|
|
858
858
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Valid enum values for every searchable field, organized by entity.
|
|
4
4
|
> For filter syntax and operators, see [search-reference.md](./search-reference.md).
|
|
5
|
-
> For
|
|
5
|
+
> For the `query` expression language and composition examples, see [search-syntax.md](./search-syntax.md).
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -110,7 +110,7 @@ org has no such account". `search_accounts` does not normalise — only
|
|
|
110
110
|
**Amount fields**: `totalAmount`, `balanceAmount`, `reconciledAmount`, `paymentRecordedAmount`, `creditAppliedAmount`
|
|
111
111
|
**Date fields**: `valueDate`, `dueDate`, `createdAt` (DateTime), `updatedAt` (DateTime), `approvedAt`, `submittedAt`
|
|
112
112
|
|
|
113
|
-
> **Note**: `OVERDUE` is not a
|
|
113
|
+
> **Note**: `OVERDUE` is not a status value (a list with it returns 422, a search matches nothing). To find overdue invoices, filter `{"status": {"in": ["UNPAID", "PARTIALLY_PAID"]}, "dueDate": {"lt": "<today in the organization's timezone>"}}`. With `search_invoices`: `status: "UNPAID,PARTIALLY_PAID"` and `dueDateTo` set to yesterday in the organization's timezone. Same for bills.
|
|
114
114
|
|
|
115
115
|
---
|
|
116
116
|
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
| `At least one line item is required` | Empty --lines array | Provide at least one line item object |
|
|
47
47
|
| `Invalid date format` | Date not in YYYY-MM-DD | Use ISO format: `--date 2026-03-15` |
|
|
48
48
|
| `unitPrice must be a number` | String passed for numeric field | Remove quotes from numeric values in JSON |
|
|
49
|
-
| `Invalid status filter` | Wrong status value for entity type | Check valid statuses per type (Rule 67): invoices/bills DRAFT, UNPAID, PARTIALLY_PAID, PAID, OVERDUE,
|
|
49
|
+
| `Invalid status filter` | Wrong status value for entity type | Check valid statuses per type (Rule 67): invoices/bills DRAFT, UNPAID, PARTIALLY_PAID, PAID, VOID (no OVERDUE status: use `--status UNPAID,PARTIALLY_PAID --due-date-to <yesterday in the organization's timezone>`); journals DRAFT, ACTIVE, VOID |
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
@@ -38,7 +38,7 @@ running. Delivered as a **422**, which reads like a validation failure and is no
|
|
|
38
38
|
|
|
39
39
|
| Message | Trigger | Recovery |
|
|
40
40
|
|---|---|---|
|
|
41
|
-
| `The SQL query feature is not available.` | The reporting service has no read-only query pool: its connection string is unset for this deployment, or the pool failed to build, ping, or match the catalog at startup | None available to you. Do not rewrite the query. Use the report tools (`
|
|
41
|
+
| `The SQL query feature is not available.` | The reporting service has no read-only query pool: its connection string is unset for this deployment, or the pool failed to build, ping, or match the catalog at startup | None available to you. Do not rewrite the query. Use the report tools (`generate_trial_balance`, `generate_profit_and_loss`, the operational report family) and tell the user the engine is off. |
|
|
42
42
|
|
|
43
43
|
**The catalog stays readable while the engine is off.** `get_pseudo_sql_schema` is served from a
|
|
44
44
|
static in-process snapshot and never touches the query pool, so it keeps returning the full table,
|
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
## Tools, recipes, calculators this job uses
|
|
6
6
|
|
|
7
7
|
### Platform tools — financial statements
|
|
8
|
-
- **`generate_trial_balance(
|
|
9
|
-
- **`generate_balance_sheet(
|
|
10
|
-
- **`generate_profit_and_loss(
|
|
11
|
-
- **`generate_cashflow(
|
|
12
|
-
- **`generate_equity_movement(
|
|
13
|
-
- **`generate_general_ledger(
|
|
8
|
+
- **`generate_trial_balance(endDate: <FY-end>)`** — step 2: master reconciliation. Every other report ties back to this.
|
|
9
|
+
- **`generate_balance_sheet(snapshotDate: <FY-end>)`** — step 3.
|
|
10
|
+
- **`generate_profit_and_loss(startDate: <FY-start>, endDate: <FY-end>)`** — step 3.
|
|
11
|
+
- **`generate_cashflow(startDate, endDate)`** — step 4.
|
|
12
|
+
- **`generate_equity_movement(primarySnapshotStartDate, primarySnapshotEndDate)`** — step 4.
|
|
13
|
+
- **`generate_general_ledger(startDate, endDate, groupBy: 'ACCOUNT')`** — step 5: the auditor's primary working document.
|
|
14
14
|
|
|
15
15
|
### Platform tools — supporting schedules
|
|
16
|
-
- **`generate_aged_ar(
|
|
17
|
-
- **`generate_bank_recon_summary(
|
|
18
|
-
- **`generate_bank_balance_summary(
|
|
19
|
-
- **`generate_fa_summary(
|
|
20
|
-
- **`generate_vat_ledger(
|
|
16
|
+
- **`generate_aged_ar(endDate)` / `generate_aged_ap(endDate)`** — step 6.
|
|
17
|
+
- **`generate_bank_recon_summary(bankAccountResourceId, primarySnapshotStartDate, primarySnapshotEndDate)` / `generate_bank_recon_details(bankAccountResourceId, primarySnapshotStartDate, primarySnapshotEndDate, filter)` per bank account** — step 7. NON-NEGOTIABLE deliverable.
|
|
18
|
+
- **`generate_bank_balance_summary(primarySnapshotDate)`** — step 7. Cross-reference to bank confirmation letters.
|
|
19
|
+
- **`generate_fa_summary(primarySnapshotStartDate, primarySnapshotEndDate, groupBy)` / `generate_fa_recon_summary(primarySnapshotStartDate, primarySnapshotEndDate)`** — step 8.
|
|
20
|
+
- **`generate_vat_ledger(startDate, endDate)`** — step 9. Annual total ties to sum of quarterly F5 returns.
|
|
21
21
|
|
|
22
22
|
### Platform tools — XLSX deliverables
|
|
23
23
|
- **`download_export(exportType: '<type>', startDate, endDate)`** — step 10: pre-signed XLSX URL (~5 min expiry). Per `jaz-api/SKILL.md` rule (data-exports), supported types include `trial-balance`, `profit-and-loss`, `balance-sheet`, `general-ledger`, `ar-report`, `ap-report`, `cashflow`, `analysis-anomalous-bills`, `analysis-anomalous-invoices`, `analysis-cashflow-anomalies`, `analysis-gl-journal-audit`, `analysis-exchange-rate-audit`, `analysis-receivables-customer-risk`, `analysis-cash-expense-health`. The audit-analyses are essential pre-emptive flags for the auditor.
|
|
@@ -61,7 +61,7 @@ The jurisdiction-specific deliverable list. SG: TB / BS / P&L / CF / EM / AR agi
|
|
|
61
61
|
## Step 2 — Trial balance (the master)
|
|
62
62
|
|
|
63
63
|
```
|
|
64
|
-
generate_trial_balance(
|
|
64
|
+
generate_trial_balance(endDate: '2025-12-31', currencyCode: <base currency>)
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
Save the FY trial balance. Verify: every report from step 3 onwards must tie back to a TB line.
|
|
@@ -69,14 +69,14 @@ Save the FY trial balance. Verify: every report from step 3 onwards must tie bac
|
|
|
69
69
|
## Step 3 — Primary financial statements
|
|
70
70
|
|
|
71
71
|
```
|
|
72
|
-
generate_balance_sheet(
|
|
73
|
-
generate_profit_and_loss(
|
|
72
|
+
generate_balance_sheet(snapshotDate: '2025-12-31')
|
|
73
|
+
generate_profit_and_loss(startDate: '2025-01-01', endDate: '2025-12-31')
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
Optional comparative:
|
|
77
77
|
```
|
|
78
|
-
generate_profit_and_loss(
|
|
79
|
-
generate_balance_sheet(
|
|
78
|
+
generate_profit_and_loss(startDate: '2024-01-01', endDate: '2024-12-31')
|
|
79
|
+
generate_balance_sheet(snapshotDate: '2024-12-31')
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
Assert: BS Total Assets = Total Liabilities + Total Equity. P&L Net Profit ties to Equity Movement (step 4) `netProfit` line.
|
|
@@ -84,8 +84,8 @@ Assert: BS Total Assets = Total Liabilities + Total Equity. P&L Net Profit ties
|
|
|
84
84
|
## Step 4 — Cashflow + Equity Movement
|
|
85
85
|
|
|
86
86
|
```
|
|
87
|
-
generate_cashflow(
|
|
88
|
-
generate_equity_movement(
|
|
87
|
+
generate_cashflow(startDate: '2025-01-01', endDate: '2025-12-31')
|
|
88
|
+
generate_equity_movement(primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-12-31')
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
Cashflow classifies into Operating / Investing / Financing per IAS 7. Equity Movement reconciles opening equity → net profit → dividends → other movements → closing equity. The closing equity must tie to BS step 3 Total Equity.
|
|
@@ -93,7 +93,7 @@ Cashflow classifies into Operating / Investing / Financing per IAS 7. Equity Mov
|
|
|
93
93
|
## Step 5 — General Ledger (auditor's working document)
|
|
94
94
|
|
|
95
95
|
```
|
|
96
|
-
generate_general_ledger(
|
|
96
|
+
generate_general_ledger(startDate: '2025-01-01', endDate: '2025-12-31', groupBy: 'ACCOUNT')
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
The tool returns 50 rows per call by default. Page it at `limit` 50-100: a GL row is about 1KB, so larger pages get cut to the tool's result cap and come back with `_truncated`. The offset is a ROW offset (`jaz-api/SKILL.md` rule 38): step it by the rows the call actually returned, which is what `_paging.nextOffset` holds, and stop when a result carries no `_paging`. Keep the full GL for the pack, since the auditor will sample-test from it. From the CLI, `clio reports generate general-ledger --all` pages it for you.
|
|
@@ -101,8 +101,8 @@ The tool returns 50 rows per call by default. Page it at `limit` 50-100: a GL ro
|
|
|
101
101
|
## Step 6 — AR / AP aging
|
|
102
102
|
|
|
103
103
|
```
|
|
104
|
-
generate_aged_ar(
|
|
105
|
-
generate_aged_ap(
|
|
104
|
+
generate_aged_ar(endDate: '2025-12-31')
|
|
105
|
+
generate_aged_ap(endDate: '2025-12-31')
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
Use `endDate` not `startDate` (rule 36 — point-in-time snapshot). Assert:
|
|
@@ -111,16 +111,16 @@ Use `endDate` not `startDate` (rule 36 — point-in-time snapshot). Assert:
|
|
|
111
111
|
|
|
112
112
|
If ECL provision feels inadequate for the > 90d bucket, run the ECL recipe immediately:
|
|
113
113
|
```
|
|
114
|
-
plan_recipe(recipe: 'ecl',
|
|
114
|
+
plan_recipe(recipe: 'ecl', buckets: <aged AR buckets as [{name, balance, rate}]>, existingProvision, startDate, ...)
|
|
115
115
|
```
|
|
116
116
|
And post any top-up provision via `execute_recipe`. This avoids an auditor-proposed adjustment at fieldwork.
|
|
117
117
|
|
|
118
118
|
## Step 7 — Bank reconciliation (NON-NEGOTIABLE)
|
|
119
119
|
|
|
120
120
|
```
|
|
121
|
-
generate_bank_recon_summary(
|
|
122
|
-
generate_bank_recon_details(
|
|
123
|
-
generate_bank_balance_summary(
|
|
121
|
+
generate_bank_recon_summary(bankAccountResourceId: <each bank account>, primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-12-31')
|
|
122
|
+
generate_bank_recon_details(bankAccountResourceId: <each bank account>, primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-12-31', filter: {valueDate: {range: ['2025-01-01', '2025-12-31']}})
|
|
123
|
+
generate_bank_balance_summary(primarySnapshotDate: '2025-12-31')
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
For each bank account: `unreconciledCount` MUST be 0 OR every unreconciled item has a documented timing-difference explanation. The auditor will request bank confirmation letters DIRECTLY from your banks — `generate_bank_balance_summary` total must reconcile to those letters within tolerance.
|
|
@@ -130,8 +130,8 @@ If `unreconciledCount > 0`: halt audit-prep and route back to `bank-recon.md` jo
|
|
|
130
130
|
## Step 8 — Fixed assets + supporting schedules
|
|
131
131
|
|
|
132
132
|
```
|
|
133
|
-
generate_fa_summary(
|
|
134
|
-
generate_fa_recon_summary(
|
|
133
|
+
generate_fa_summary(primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-12-31', groupBy: 'CATEGORY')
|
|
134
|
+
generate_fa_recon_summary(primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-12-31')
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Assert: `fa_recon.openingNbv + additions - disposals - depreciation == fa_recon.closingNbv == TB['Fixed Assets'].balance`.
|
|
@@ -145,7 +145,7 @@ For each capsule, run the matching `clio calc <type>` to produce the independent
|
|
|
145
145
|
## Step 9 — Tax ledger
|
|
146
146
|
|
|
147
147
|
```
|
|
148
|
-
generate_vat_ledger(
|
|
148
|
+
generate_vat_ledger(startDate: '2025-01-01', endDate: '2025-12-31')
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
For SG: annual total ties to sum of 4 quarterly GST F5 returns. For PH: annual total ties to monthly VAT returns + quarterly summary. The annual reconciliation should already be clean if the `gst-vat-filing.md` job ran each period.
|
|
@@ -223,8 +223,8 @@ The SG Form C-S wizard walks the user field-by-field through the C-S form, prefi
|
|
|
223
223
|
| `generate_bank_recon_*` | `unreconciledCount > 0` | Route to `bank-recon.md`; do NOT hand pack with this open. |
|
|
224
224
|
| `download_export` | 422 `period_too_long` | GL XLSX rejected for >12 months. Split into per-quarter exports. |
|
|
225
225
|
| `download_export` | 504 timeout | Large org. Re-run with smaller `endDate` range or contact infrastructure team. |
|
|
226
|
-
| `update_account` | 422 `lock_date_in_future` | The CoA `lockDate` must be ≤
|
|
227
|
-
| Reconciliation | TB AR ≠ AR aging | Likely a mid-period credit-note application missed. `search_customer_credit_notes(filter: {valueDate: {between: ...}})` and verify each was applied via `
|
|
226
|
+
| `update_account` | 422 `lock_date_in_future` | The CoA `lockDate` must be ≤ the period end date. Use today if unsure. |
|
|
227
|
+
| Reconciliation | TB AR ≠ AR aging | Likely a mid-period credit-note application missed. `search_customer_credit_notes(filter: {valueDate: {between: ...}})` and verify each was applied via `apply_credits_to_invoice`. |
|
|
228
228
|
| Reconciliation | TB Cash ≠ bank balance summary | Unposted bank journal or unreconciled item. Re-run step 7. |
|
|
229
229
|
| Step 12 gate | Drafts present at year-end | Either clear (finalize) or document the residuals and surface to the user. NEVER hand the pack over with drafts in the audit period. |
|
|
230
230
|
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
- **`reconcile_cash_transfer(...)`** — inter-account transfer.
|
|
30
30
|
|
|
31
31
|
### Platform tools — create missing transactions
|
|
32
|
-
- **`mcp magic create --file <pdf>` / `
|
|
33
|
-
- **`
|
|
32
|
+
- **`mcp magic create --file <pdf>` / `create_bt_from_attachment(...)`** — step 6 path B: OCR + autofill bill or invoice from receipt PDF/JPG.
|
|
33
|
+
- **`create_cash_in(...)` / `create_cash_out(...)`** — step 6 path C: bank fees, interest, FX charges that have no source document.
|
|
34
34
|
- **`create_bank_rule(...)`** — preventive: build a rule for any recurring pattern you handled this run (subscription, rent, utility) so it auto-applies next time.
|
|
35
35
|
|
|
36
36
|
### Platform tools — verification
|
|
37
|
-
- **`generate_bank_recon_summary(
|
|
38
|
-
- **`generate_bank_recon_details(
|
|
39
|
-
- **`generate_bank_balance_summary(
|
|
37
|
+
- **`generate_bank_recon_summary(bankAccountResourceId, primarySnapshotStartDate, primarySnapshotEndDate)`** — step 7: per-account formal recon statement.
|
|
38
|
+
- **`generate_bank_recon_details(bankAccountResourceId, primarySnapshotStartDate, primarySnapshotEndDate, filter: {valueDate: {range: [from, to]}})`** — step 7: line-level recon detail for audit pack.
|
|
39
|
+
- **`generate_bank_balance_summary(primarySnapshotDate)`** — step 8: book balance vs bank statement balance per account.
|
|
40
40
|
|
|
41
41
|
### CLI tools — bulk auto-match cascade (offline)
|
|
42
42
|
- **`clio jobs bank-recon match --input <records.json> --tolerance 0.01 --date-window 14 --max-group 5 --json`** — the 5-phase cascade matcher (Phase 1 exact 1:1 hash join, Phase 2 fuzzy 1:1 greedy with weighted scoring, Phase 3 N:1, Phase 4 1:N, Phase 5 N:M). Returns matches sorted by confidence — feed each into the appropriate `reconcile_*` tool. See `bank-match.md` for the full algorithm.
|
|
@@ -83,7 +83,7 @@ Flag any item older than 60 days as red — surface to practitioner.
|
|
|
83
83
|
search_bank_records(accountResourceId: B.resourceId, status: 'POSSIBLE_DUPLICATE', limit: 200)
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Two bank-feed entries with same `valueDate + netAmount + description` = system-flagged duplicate. Review each pair
|
|
86
|
+
Two bank-feed entries with same `valueDate + netAmount + description` = system-flagged duplicate. Review each pair and ask the user to archive the duplicate in the Jaz app BEFORE running step 4 (no tool archives a bank record). Until it is archived, reconcile neither row of the pair: reconciling a duplicated row creates double cashflow entries.
|
|
87
87
|
|
|
88
88
|
Record the judgment per archived pair: `jot(kind: MATCH)` naming the kept entry, the archived entry, and the tie-breaker used.
|
|
89
89
|
|
|
@@ -158,33 +158,30 @@ For unreconciled rows that have no book-side counterpart yet:
|
|
|
158
158
|
```
|
|
159
159
|
mcp magic create --file <invoice-or-receipt-path>
|
|
160
160
|
# OR equivalent MCP call:
|
|
161
|
-
|
|
162
|
-
sourceFile: <base64 or upload>,
|
|
161
|
+
create_bt_from_attachment(
|
|
163
162
|
businessTransactionType: 'BILL' | 'INVOICE',
|
|
164
|
-
|
|
163
|
+
sourceUrl: <file URL> // omit when the host attaches the file to the call
|
|
165
164
|
)
|
|
166
165
|
```
|
|
167
166
|
Magic does OCR + line item extraction + contact matching + CoA suggestion. Returns draft. Review, finalize via `finalize_bill` / `finalize_invoice`, then loop back to step 4 to reconcile.
|
|
168
167
|
|
|
169
168
|
**Path C — bank fees / interest / FX charges (no document):**
|
|
170
169
|
```
|
|
171
|
-
|
|
170
|
+
create_cash_out(
|
|
172
171
|
reference: 'BANK-FEE-2025-01-15-001',
|
|
173
172
|
valueDate: '2025-01-15',
|
|
174
173
|
accountResourceId: <bank-account-id>,
|
|
175
174
|
lines: [{
|
|
176
175
|
accountResourceId: <Bank Charges expense GL>,
|
|
177
176
|
amount: 25.00,
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}],
|
|
181
|
-
saveAsDraft: false
|
|
177
|
+
description: 'Monthly service charge, Jan 2025'
|
|
178
|
+
}]
|
|
182
179
|
)
|
|
183
180
|
```
|
|
184
181
|
|
|
185
|
-
Per rule 26: `accountResourceId` at top level is the BANK account; `lines[]` carries the offset (expense / income).
|
|
182
|
+
Per rule 26: `accountResourceId` at top level is the BANK account; `lines[]` carries the offset (expense / income). Cash lines take no `type`: the endpoint sets the direction.
|
|
186
183
|
|
|
187
|
-
For interest income: `
|
|
184
|
+
For interest income: `create_cash_in(...)` with a line against `Interest Income`.
|
|
188
185
|
|
|
189
186
|
After creating, loop back to step 4 to reconcile.
|
|
190
187
|
|
|
@@ -223,8 +220,8 @@ search_bank_records(accountResourceId: B.resourceId, status: 'UNRECONCILED', lim
|
|
|
223
220
|
Target: zero rows OR all remaining are documented timing differences (outstanding cheques, deposits in transit clearing next period — practitioner annotates). Record the judgment: `jot(kind: SCOPE)` naming each residual accepted as a timing difference and why it clears next period.
|
|
224
221
|
|
|
225
222
|
```
|
|
226
|
-
generate_bank_recon_summary(
|
|
227
|
-
generate_bank_recon_details(
|
|
223
|
+
generate_bank_recon_summary(bankAccountResourceId: B.resourceId, primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-01-31')
|
|
224
|
+
generate_bank_recon_details(bankAccountResourceId: B.resourceId, primarySnapshotStartDate: '2025-01-01', primarySnapshotEndDate: '2025-01-31', filter: {valueDate: {range: ['2025-01-01', '2025-01-31']}})
|
|
228
225
|
```
|
|
229
226
|
|
|
230
227
|
Keep both the summary and the line-level detail per account — audit-prep step 7 will require them.
|
|
@@ -232,7 +229,7 @@ Keep both the summary and the line-level detail per account — audit-prep step
|
|
|
232
229
|
## Step 8 — Cross-account verify
|
|
233
230
|
|
|
234
231
|
```
|
|
235
|
-
generate_bank_balance_summary(
|
|
232
|
+
generate_bank_balance_summary(primarySnapshotDate: '2025-01-31')
|
|
236
233
|
```
|
|
237
234
|
|
|
238
235
|
Per account: `bookBalance == bankStatementBalance ± documentedTimingDifference`. Discrepancy = unreconciled item missed → loop back to step 2 for that account.
|
|
@@ -253,9 +250,9 @@ Per account: `bookBalance == bankStatementBalance ± documentedTimingDifference`
|
|
|
253
250
|
| `reconcile_with_payments` | 422 `TOTAL_RECONCILIATION_AMOUNT_MISMATCHED...` | Payments + adjustments ≠ bank entry amount. Add the delta as an `adjustment.cashAdjustmentEntries[]` leg (over/under-payment or FX write-off) so the total matches, then resend. |
|
|
254
251
|
| `reconcile_with_payments` | 422 `...does not exist` / invalid status | The BT isn't an open bill/invoice (wrong id, already paid, or draft). Re-fetch via `search_cashflow_transactions`; finalize if draft. |
|
|
255
252
|
| `reconcile_invoice_receipt` | 422 `invoice_status_invalid` | Matched invoice still DRAFT. `finalize_invoice(resourceId: <id>)` first. |
|
|
256
|
-
| `reconcile_invoice_receipt` | 422 `amount_mismatch` | Bank amount ≠ invoice balance. Either partial payment (post via `
|
|
253
|
+
| `reconcile_invoice_receipt` | 422 `amount_mismatch` | Bank amount ≠ invoice balance. Either partial payment (post via `pay_invoice` with partial amount, then reconcile), or wrong match (revisit step 4/5). |
|
|
257
254
|
| `apply_bank_rule` | 422 `rule_action_unsupported` | Rule's configured action doesn't match the bank entry shape (e.g., rule expects positive amount, entry is negative). Edit the rule via `update_bank_rule`. |
|
|
258
|
-
| `
|
|
255
|
+
| `create_cash_out` | 422 `lock_date_violated` | `valueDate` in locked period. Lift lock via `update_account` lockDate, post, re-lock. |
|
|
259
256
|
| Step 7 `unreconciledCount > 0` after step 6 | (residual misses) | Surface to the user with categorized residual ("3 bank charges to expense via path C, 1 unidentified deposit pending client query"). Record the residuals. Do NOT progress the month-end close with open items. |
|
|
260
257
|
|
|
261
258
|
---
|
|
@@ -18,7 +18,7 @@ Period derivation:
|
|
|
18
18
|
|
|
19
19
|
**Period boundaries matter for:**
|
|
20
20
|
- `search_*` filters — `{valueDate: {between: [<period-start>, <period-end>]}}` per `jaz-api/SKILL.md` rule 2.
|
|
21
|
-
- Reports — `
|
|
21
|
+
- Reports — each tool names its own dates: `endDate` (trial balance, aged AR/AP, cash balance), `snapshotDate` (balance sheet), `startDate` + `endDate` (P&L, cashflow, general ledger, VAT ledger), `primarySnapshotStartDate` + `primarySnapshotEndDate` (FA summary/recon, equity movement, bank recon), `primarySnapshotDate` (bank balance summary).
|
|
22
22
|
- Lock dates — `update_account` lockDate sets the close marker.
|
|
23
23
|
|
|
24
24
|
## Lock dates
|
|
@@ -36,17 +36,17 @@ Per-account locks (rare): set `lockDate` on a specific bank account or controlle
|
|
|
36
36
|
Run after every period close:
|
|
37
37
|
|
|
38
38
|
```
|
|
39
|
-
generate_trial_balance(
|
|
40
|
-
generate_profit_and_loss(
|
|
41
|
-
generate_balance_sheet(
|
|
39
|
+
generate_trial_balance(endDate: <period-end>)
|
|
40
|
+
generate_profit_and_loss(startDate: <period-start>, endDate: <period-end>)
|
|
41
|
+
generate_balance_sheet(snapshotDate: <period-end>)
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Standard assertions:
|
|
45
45
|
- TB: `Debits == Credits` (always; if not, system bug).
|
|
46
46
|
- BS: `Total Assets == Total Liabilities + Total Equity`.
|
|
47
|
-
- TB AR == `generate_aged_ar(
|
|
48
|
-
- TB AP == `generate_aged_ap(
|
|
49
|
-
- TB Cash == `generate_bank_balance_summary(
|
|
47
|
+
- TB AR == `generate_aged_ar(endDate)` total.
|
|
48
|
+
- TB AP == `generate_aged_ap(endDate)` total.
|
|
49
|
+
- TB Cash == `generate_bank_balance_summary(primarySnapshotDate)` per-bank total (via `bank-recon.md`).
|
|
50
50
|
|
|
51
51
|
## Pre-emitted DRAFT journal pattern
|
|
52
52
|
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
## Tools, recipes, calculators this job uses
|
|
6
6
|
|
|
7
7
|
### Platform tools
|
|
8
|
-
- **`generate_aged_ar(
|
|
8
|
+
- **`generate_aged_ar(endDate: <date>)`** — step 1: AR aging report with bucket breakdown.
|
|
9
9
|
- **`search_invoices(filter: {status: {eq: 'UNPAID'}, dueDate: {lt: <date>}, contactResourceId: <customer>}, sortBy: 'dueDate', sortOrder: 'ASC', limit: 200)`** — step 2: per-customer overdue detail. Paginate.
|
|
10
10
|
- **`get_contact(resourceId: <customer id>)`** — step 2: pull contact info (email, phone, primary contact).
|
|
11
11
|
- **`get_contact_signals(resourceId: <id>, btType: 'SALE')`** — step 3: pull cadence + outlier signals + outstanding balance for the customer. Mid-7 endpoint.
|
|
12
|
-
- **`
|
|
13
|
-
- **`
|
|
12
|
+
- **`apply_credits_to_invoice(...)`** / **`create_customer_credit_note(...)`** — step 6: write-off path A for stage-3 specific impairment.
|
|
13
|
+
- **`pay_invoice(... paymentMethod: 'DEBT_WRITE_OFF' ...)`** — step 6: write-off path B (direct).
|
|
14
14
|
- **`plan_recipe(recipe: 'ecl', ...)` + `execute_recipe(...)`** — step 7: ECL collective top-up if material change in aging.
|
|
15
15
|
- **`download_export(exportType: 'analysis-receivables-customer-risk', startDate, endDate)`** — step 8: pre-empt audit by surfacing high-risk customers.
|
|
16
16
|
|
|
@@ -28,7 +28,7 @@ Walk steps 1-8 below. (Local CLI: `clio jobs credit-control --overdue-days 30` p
|
|
|
28
28
|
## Step 1 — AR aging snapshot
|
|
29
29
|
|
|
30
30
|
```
|
|
31
|
-
generate_aged_ar(
|
|
31
|
+
generate_aged_ar(endDate: '2025-01-31')
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Save the AR aging snapshot. Returns aging buckets (current, 30d, 60d, 90d, 120d+) per customer. Total per bucket informs collection priority.
|
|
@@ -93,7 +93,7 @@ For each customer chased: keep a chase log with:
|
|
|
93
93
|
- Promised payment date (if any)
|
|
94
94
|
- Next action date
|
|
95
95
|
|
|
96
|
-
Capsule alternative: `create_capsule(
|
|
96
|
+
Capsule alternative: `create_capsule(capsuleTypeResourceId: <id of 'Bad Debt Write-off' from list_capsule_types>, title: 'Credit Control — <customer> — FY2025')` with the chase log as the description; attach any eventual write-off journal / credit note to the same capsule for audit trail.
|
|
97
97
|
|
|
98
98
|
## Step 6 — Specific write-off (stage-3 impairment)
|
|
99
99
|
|
|
@@ -108,26 +108,25 @@ create_customer_credit_note(
|
|
|
108
108
|
lineItems: [{
|
|
109
109
|
name: 'Write-off — uncollectible (formal insolvency)',
|
|
110
110
|
accountResourceId: <Bad Debt Expense GL>,
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
quantity: 1,
|
|
112
|
+
unitPrice: <balance to write off>
|
|
113
113
|
}],
|
|
114
|
+
saveAsDraft: false,
|
|
114
115
|
capsuleResourceId: <credit-control capsule>
|
|
115
116
|
)
|
|
116
|
-
|
|
117
|
+
apply_credits_to_invoice(resourceId: <inv>, credits: [{creditNoteResourceId: <cn>, amountApplied: <balance>}])
|
|
117
118
|
```
|
|
118
119
|
|
|
119
120
|
**Path B — direct write-off**:
|
|
120
121
|
```
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
valueDate: '2025-01-31'
|
|
130
|
-
}]
|
|
122
|
+
pay_invoice(
|
|
123
|
+
resourceId: <inv>,
|
|
124
|
+
paymentAmount: <balance>,
|
|
125
|
+
transactionAmount: <balance>,
|
|
126
|
+
accountResourceId: <Bad Debt Expense GL>,
|
|
127
|
+
paymentMethod: 'DEBT_WRITE_OFF',
|
|
128
|
+
reference: 'WRITE-OFF-<inv>',
|
|
129
|
+
valueDate: '2025-01-31'
|
|
131
130
|
)
|
|
132
131
|
```
|
|
133
132
|
|
|
@@ -145,9 +144,9 @@ clio calc ecl --current <c> --30d <30> --60d <60> --90d <90> --120d <120> --rate
|
|
|
145
144
|
|
|
146
145
|
If `topUpRequired > materiality threshold`:
|
|
147
146
|
```
|
|
148
|
-
plan_recipe(recipe: 'ecl',
|
|
149
|
-
execute_recipe(...)
|
|
150
|
-
|
|
147
|
+
plan_recipe(recipe: 'ecl', ...)
|
|
148
|
+
execute_recipe(...) // creates its own ECL Provision capsule; regroup with move_transaction_capsules if needed
|
|
149
|
+
bulk_update_journals(items: [{resourceId: <id>, saveAsDraft: false}, ...])
|
|
151
150
|
```
|
|
152
151
|
|
|
153
152
|
Note: monthly ECL is typically a mental check; formal ECL provision recompute is quarterly (per `quarter-end-close.md` Q2). Trigger this monthly only on material shifts.
|
|
@@ -168,7 +167,7 @@ Returns XLSX with high-risk customer flags (rising aging trends, recently-defaul
|
|
|
168
167
|
|--------|-------|----------|
|
|
169
168
|
| Step 2 | `search_invoices` returns 0 despite aging shows overdue | Aging report may include `PARTIALLY_PAID` invoices; expand filter `status: {in: ['UNPAID', 'PARTIALLY_PAID']}`. |
|
|
170
169
|
| Step 3 | `get_contact_signals` returns `null` | The freshness layer is offline; skip the signals step and use aging alone. Don't halt the job. |
|
|
171
|
-
| Step 6 Path A | `
|
|
170
|
+
| Step 6 Path A | `apply_credits_to_invoice` 422 `credit_exceeds_balance` | Split the credit across multiple invoices, OR reduce the credit amount to match the bill balance. |
|
|
172
171
|
| Step 6 Path B | `paymentMethod: 'DEBT_WRITE_OFF'` rejected | Verify the enum value via `jaz-api/SKILL.md` (some orgs may have custom payment-method config; default supports DEBT_WRITE_OFF). |
|
|
173
172
|
| Step 7 ECL recipe | Top-up causes Bad Debt Expense to spike | Expected — material aging shift = material P&L impact. Surface to practitioner; potentially split across multiple periods if it's a known one-off (rare). |
|
|
174
173
|
| Customer files insolvency mid-chase | (process) | Stop chase. Move directly to step 6 specific write-off. Document the insolvency filing reference. |
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
## Tools, recipes, calculators this job uses
|
|
6
6
|
|
|
7
7
|
### Platform tools
|
|
8
|
-
- **`mcp magic create --file <pdf>` / `
|
|
8
|
+
- **`mcp magic create --file <pdf>` / `create_bt_from_attachment(businessTransactionType: 'BILL'|'INVOICE'|'CUSTOMER_CREDIT_NOTE'|'SUPPLIER_CREDIT_NOTE', sourceUrl)`** — step 4: OCR + line-item extraction + contact + CoA suggestion. Creates DRAFT transaction.
|
|
9
9
|
- **`finalize_bill(...)` / `finalize_invoice(...)` / `finalize_customer_credit_note(...)`** — step 5: finalize practitioner-reviewed Magic-extracted DRAFTs.
|
|
10
|
-
- **`import_bank_statement(
|
|
10
|
+
- **`import_bank_statement(accountResourceId, sourceUrl | attachmentId)`** — step 6: bank statements (CSV / OFX / PDF); creates bank records pending reconciliation per `bank-recon.md`.
|
|
11
11
|
- **`search_background_jobs(filter: {resourceId: {eq: <jobId>}})`** — step 7: poll Magic / bank-import async jobs to terminal status.
|
|
12
12
|
|
|
13
13
|
### CLI tools (jaz-cli — offline)
|
|
@@ -88,10 +88,9 @@ For each file with `suggestedAction: 'magic-create-bill' | 'magic-create-invoice
|
|
|
88
88
|
```
|
|
89
89
|
mcp magic create --file <decrypted path> --type bill
|
|
90
90
|
# OR equivalent MCP call:
|
|
91
|
-
|
|
92
|
-
sourceFile: <multipart upload>,
|
|
91
|
+
create_bt_from_attachment(
|
|
93
92
|
businessTransactionType: 'BILL',
|
|
94
|
-
|
|
93
|
+
sourceUrl: <file URL> // omit when the host attaches the file to the call
|
|
95
94
|
)
|
|
96
95
|
```
|
|
97
96
|
|
|
@@ -117,7 +116,7 @@ When approved:
|
|
|
117
116
|
```
|
|
118
117
|
finalize_bill(resourceId: <id>)
|
|
119
118
|
# OR for batch:
|
|
120
|
-
bulk_finalize_drafts({
|
|
119
|
+
bulk_finalize_drafts(items: [{type: 'bill', resourceId: <id>}, ...])
|
|
121
120
|
```
|
|
122
121
|
|
|
123
122
|
## Step 6 — Bank statement import
|
|
@@ -133,9 +132,8 @@ Match by name + currency to the statement (typically the bank logo + account num
|
|
|
133
132
|
|
|
134
133
|
```
|
|
135
134
|
import_bank_statement(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
sourceType: 'FILE'
|
|
135
|
+
accountResourceId: <bank id>,
|
|
136
|
+
sourceUrl: <statement file URL> // or attachmentId
|
|
139
137
|
)
|
|
140
138
|
```
|
|
141
139
|
|
|
@@ -174,9 +172,9 @@ Auditor sample-test traces from a posted bill back to the source PDF. Audit trai
|
|
|
174
172
|
| Step 4 Magic | 422 `unsupported_file_type` | Convert to PDF / JPG first. Excel / Word formats not supported by Magic OCR. |
|
|
175
173
|
| Step 4 Magic | Job stays in QUEUED for > 5 minutes | Magic queue is backed up. Check status; consider manual posting if blocking close. |
|
|
176
174
|
| Step 4 Magic | `PARTIAL_SUCCESS` with low-confidence extractions | Review each in step 5; practitioner overrides. Magic confidence < 0.7 = manual review required. |
|
|
177
|
-
| Step 5 review | Wrong contact assigned | `update_bill(
|
|
175
|
+
| Step 5 review | Wrong contact assigned | `update_bill(resourceId: <bill id>, ...)` does not take `contactResourceId`: delete the draft and re-create it against the correct contact, then finalize. |
|
|
178
176
|
| Step 5 review | Wrong line-item GL | `update_bill(lineItems: [<corrected>])` before finalize. |
|
|
179
|
-
| Step 6 bank import | 422 `bank_format_unsupported` | Bank format not supported (some niche banks). Manual `add_bank_records(
|
|
177
|
+
| Step 6 bank import | 422 `bank_format_unsupported` | Bank format not supported (some niche banks). Manual `add_bank_records(accountResourceId, records: [...])` per statement line. |
|
|
180
178
|
| Step 7 polling | Job stuck in PROCESSING > 10 minutes | Escalate; usually a Magic backend issue. |
|
|
181
179
|
|
|
182
180
|
---
|