jaz-cli 2.6.0 → 2.8.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.
Files changed (62) hide show
  1. package/assets/skills/api/SKILL.md +12 -2
  2. package/assets/skills/api/references/dependencies.md +3 -2
  3. package/assets/skills/api/references/endpoints.md +78 -0
  4. package/assets/skills/api/references/feature-glossary.md +4 -4
  5. package/assets/skills/api/references/field-map.md +17 -0
  6. package/assets/skills/api/references/full-api-surface.md +1 -1
  7. package/assets/skills/conversion/SKILL.md +1 -1
  8. package/assets/skills/jobs/SKILL.md +104 -0
  9. package/assets/skills/jobs/references/audit-prep.md +319 -0
  10. package/assets/skills/jobs/references/bank-recon.md +234 -0
  11. package/assets/skills/jobs/references/building-blocks.md +135 -0
  12. package/assets/skills/jobs/references/credit-control.md +273 -0
  13. package/assets/skills/jobs/references/fa-review.md +267 -0
  14. package/assets/skills/jobs/references/gst-vat-filing.md +250 -0
  15. package/assets/skills/jobs/references/month-end-close.md +308 -0
  16. package/assets/skills/jobs/references/payment-run.md +246 -0
  17. package/assets/skills/jobs/references/quarter-end-close.md +268 -0
  18. package/assets/skills/jobs/references/supplier-recon.md +330 -0
  19. package/assets/skills/jobs/references/year-end-close.md +341 -0
  20. package/assets/skills/transaction-recipes/SKILL.md +1 -1
  21. package/dist/__tests__/amortization.test.js +101 -0
  22. package/dist/__tests__/asset-disposal.test.js +249 -0
  23. package/dist/__tests__/blueprint.test.js +72 -0
  24. package/dist/__tests__/depreciation.test.js +125 -0
  25. package/dist/__tests__/ecl.test.js +134 -0
  26. package/dist/__tests__/fixed-deposit.test.js +214 -0
  27. package/dist/__tests__/fx-reval.test.js +115 -0
  28. package/dist/__tests__/jobs-audit-prep.test.js +125 -0
  29. package/dist/__tests__/jobs-bank-recon.test.js +108 -0
  30. package/dist/__tests__/jobs-credit-control.test.js +98 -0
  31. package/dist/__tests__/jobs-fa-review.test.js +104 -0
  32. package/dist/__tests__/jobs-gst-vat.test.js +113 -0
  33. package/dist/__tests__/jobs-month-end.test.js +162 -0
  34. package/dist/__tests__/jobs-payment-run.test.js +106 -0
  35. package/dist/__tests__/jobs-quarter-end.test.js +155 -0
  36. package/dist/__tests__/jobs-supplier-recon.test.js +115 -0
  37. package/dist/__tests__/jobs-validate.test.js +181 -0
  38. package/dist/__tests__/jobs-year-end.test.js +149 -0
  39. package/dist/__tests__/lease.test.js +96 -0
  40. package/dist/__tests__/loan.test.js +80 -0
  41. package/dist/__tests__/provision.test.js +141 -0
  42. package/dist/__tests__/validate.test.js +81 -0
  43. package/dist/calc/asset-disposal.js +17 -13
  44. package/dist/calc/fixed-deposit.js +26 -17
  45. package/dist/calc/lease.js +7 -3
  46. package/dist/commands/jobs.js +184 -0
  47. package/dist/index.js +2 -0
  48. package/dist/jobs/audit-prep.js +211 -0
  49. package/dist/jobs/bank-recon.js +163 -0
  50. package/dist/jobs/credit-control.js +126 -0
  51. package/dist/jobs/fa-review.js +121 -0
  52. package/dist/jobs/format.js +102 -0
  53. package/dist/jobs/gst-vat.js +187 -0
  54. package/dist/jobs/month-end.js +232 -0
  55. package/dist/jobs/payment-run.js +199 -0
  56. package/dist/jobs/quarter-end.js +135 -0
  57. package/dist/jobs/supplier-recon.js +132 -0
  58. package/dist/jobs/types.js +36 -0
  59. package/dist/jobs/validate.js +115 -0
  60. package/dist/jobs/year-end.js +153 -0
  61. package/dist/types/index.js +2 -1
  62. package/package.json +5 -2
@@ -0,0 +1,234 @@
1
+ # Bank Reconciliation Catch-Up
2
+
3
+ Clear unreconciled bank statement entries by matching them to existing transactions, creating missing ones, and flagging duplicates. This is the single most impactful thing you can do for book accuracy — a clean bank recon means cash is right, and cash being right means everything else has a fighting chance.
4
+
5
+ **CLI:** `jaz jobs bank-recon [--account "DBS Current"] [--period 2025-01] [--json]`
6
+
7
+ ---
8
+
9
+ ## Phase 1: Identify Bank Accounts
10
+
11
+ List all bank accounts in the org. If `--account` is specified, filter to that one. Otherwise, reconcile all of them.
12
+
13
+ ### Step 1: List bank accounts
14
+
15
+ ```
16
+ GET /api/v1/bank-accounts?limit=100&offset=0
17
+ ```
18
+
19
+ Or via CoA search (more reliable — gives you the resourceId directly):
20
+
21
+ ```
22
+ POST /api/v1/chart-of-accounts/search
23
+ {
24
+ "filter": { "accountType": { "eq": "Bank Accounts" } },
25
+ "sort": { "sortBy": ["name"], "order": "ASC" }
26
+ }
27
+ ```
28
+
29
+ **What you get:** A list of bank-type CoA accounts with `resourceId`, `name`, `currencyCode`. You need the `resourceId` for every subsequent step.
30
+
31
+ ---
32
+
33
+ ## Phase 2: Pull Unreconciled Items
34
+
35
+ For each bank account, pull all unreconciled bank records. This is your working list.
36
+
37
+ ### Step 2: Search unreconciled bank records
38
+
39
+ ```
40
+ POST /api/v1/bank-records/{accountResourceId}/search
41
+ {
42
+ "filter": {
43
+ "status": { "eq": "UNRECONCILED" },
44
+ "valueDate": { "between": ["2025-01-01", "2025-01-31"] }
45
+ },
46
+ "sort": { "sortBy": ["valueDate"], "order": "ASC" },
47
+ "limit": 1000
48
+ }
49
+ ```
50
+
51
+ **Omit the `valueDate` filter** if you want to see ALL unreconciled items regardless of date. For a catch-up, you usually want everything.
52
+
53
+ **What to check:**
54
+ - Count of unreconciled items — this is your work queue
55
+ - Any items older than 60 days are red flags (investigate immediately)
56
+ - `netAmount` positive = cash-in, negative = cash-out
57
+ - `extContactName` and `description` are your best clues for matching
58
+
59
+ ### Step 3: Check for possible duplicates
60
+
61
+ ```
62
+ POST /api/v1/bank-records/{accountResourceId}/search
63
+ {
64
+ "filter": { "status": { "eq": "POSSIBLE_DUPLICATE" } },
65
+ "sort": { "sortBy": ["valueDate"], "order": "ASC" },
66
+ "limit": 1000
67
+ }
68
+ ```
69
+
70
+ **Handle duplicates first.** If two bank feed entries have the same date, amount, and description, the system flags them as `POSSIBLE_DUPLICATE`. Review and archive the genuine duplicates before proceeding — otherwise you'll create double entries trying to reconcile them.
71
+
72
+ ---
73
+
74
+ ## Phase 3: Categorize and Resolve
75
+
76
+ Work through each unreconciled item. There are four resolution paths.
77
+
78
+ ### Path A: Match to existing transaction
79
+
80
+ The bank record matches an invoice payment, bill payment, or journal already in the books. This is the ideal case — the transaction exists, it just hasn't been linked to the bank record.
81
+
82
+ **How to find the match:** Search cashflow transactions for the same amount and approximate date:
83
+
84
+ ```
85
+ POST /api/v1/cashflow-transactions/search
86
+ {
87
+ "filter": {
88
+ "organizationAccountResourceId": { "eq": "<bank-account-uuid>" },
89
+ "totalAmount": { "eq": 2500.00 },
90
+ "valueDate": { "between": ["2025-01-10", "2025-01-20"] }
91
+ },
92
+ "sort": { "sortBy": ["valueDate"], "order": "DESC" },
93
+ "limit": 20
94
+ }
95
+ ```
96
+
97
+ **Tip:** Widen the date range by a few days — bank processing delays mean the book date and bank date often differ by 1-3 business days.
98
+
99
+ ### Path B: Create missing transaction from attachment
100
+
101
+ The bank record represents a real transaction, but nothing has been entered in the books yet. If you have the receipt, invoice, or bill document, use Jaz Magic to create the transaction automatically.
102
+
103
+ ```
104
+ POST /api/v1/magic/createBusinessTransactionFromAttachment
105
+ Content-Type: multipart/form-data
106
+
107
+ Fields:
108
+ - sourceFile: <PDF or JPG of the invoice/receipt>
109
+ - businessTransactionType: "BILL" (for expenses) or "INVOICE" (for income)
110
+ - sourceType: "FILE"
111
+ ```
112
+
113
+ Jaz Magic handles OCR, line item extraction, contact matching, and CoA mapping. It creates a draft transaction that you review and post.
114
+
115
+ **When you don't have a document:** Create the transaction manually using the appropriate endpoint (invoice, bill, cash-in, cash-out).
116
+
117
+ ### Path C: Create cash journal for bank fees/charges
118
+
119
+ Bank fees, interest charges, service charges, and similar items don't have a corresponding invoice or bill. Record them as cash-out journals.
120
+
121
+ ```
122
+ POST /api/v1/cash-out-journals
123
+ {
124
+ "saveAsDraft": false,
125
+ "reference": "BANK-FEE-JAN25-001",
126
+ "valueDate": "2025-01-15",
127
+ "accountResourceId": "<bank-account-uuid>",
128
+ "journalEntries": [
129
+ { "accountResourceId": "<bank-fees-expense-uuid>", "amount": 25.00, "type": "DEBIT", "name": "Monthly service charge — Jan 2025" }
130
+ ]
131
+ }
132
+ ```
133
+
134
+ For bank interest earned (cash-in):
135
+
136
+ ```
137
+ POST /api/v1/cash-in-journals
138
+ {
139
+ "saveAsDraft": false,
140
+ "reference": "BANK-INT-JAN25-001",
141
+ "valueDate": "2025-01-31",
142
+ "accountResourceId": "<bank-account-uuid>",
143
+ "journalEntries": [
144
+ { "accountResourceId": "<interest-income-uuid>", "amount": 12.50, "type": "CREDIT", "name": "Interest earned — Jan 2025" }
145
+ ]
146
+ }
147
+ ```
148
+
149
+ ### Path D: Flag for investigation
150
+
151
+ Some items don't have an obvious match or explanation. Flag these for the business owner or finance manager to investigate. Common causes:
152
+ - Personal transactions through the business account
153
+ - Refunds or chargebacks
154
+ - Intercompany transfers not yet recorded
155
+ - Errors in the bank feed (rare but happens)
156
+
157
+ ---
158
+
159
+ ## Phase 4: Verification
160
+
161
+ After resolving all items, verify the reconciliation is clean.
162
+
163
+ ### Step 4: Re-check unreconciled count
164
+
165
+ ```
166
+ POST /api/v1/bank-records/{accountResourceId}/search
167
+ {
168
+ "filter": { "status": { "eq": "UNRECONCILED" } },
169
+ "sort": { "sortBy": ["valueDate"], "order": "ASC" },
170
+ "limit": 1
171
+ }
172
+ ```
173
+
174
+ **Target:** Zero unreconciled items for the period, or only genuine timing differences (outstanding cheques, deposits in transit that will clear next period).
175
+
176
+ ### Step 5: Bank balance summary
177
+
178
+ ```
179
+ POST /api/v1/generate-reports/bank-balance-summary
180
+ { "primarySnapshotDate": "2025-01-31" }
181
+ ```
182
+
183
+ **What to check:**
184
+ - Book balance per Jaz should match the bank statement closing balance
185
+ - Any difference should equal the sum of known timing items
186
+ - Zero unreconciled difference = clean recon
187
+
188
+ ### Step 6: Bank reconciliation summary report
189
+
190
+ ```
191
+ POST /api/v1/generate-reports/bank-reconciliation-summary
192
+ { "primarySnapshotDate": "2025-01-31" }
193
+ ```
194
+
195
+ This gives you the formal reconciliation statement showing: opening balance + cash in - cash out = closing balance, with the reconciling items listed.
196
+
197
+ ---
198
+
199
+ ## Bank Recon Checklist (Quick Reference)
200
+
201
+ | # | Step | Phase | What |
202
+ |---|------|-------|------|
203
+ | 1 | List bank accounts | Identify | Get all bank-type CoA accounts |
204
+ | 2 | Pull unreconciled items | Pull | Search by status = UNRECONCILED |
205
+ | 3 | Check duplicates | Pull | Review POSSIBLE_DUPLICATE items |
206
+ | A | Match to existing | Resolve | Link to existing invoice/bill/journal |
207
+ | B | Create from attachment | Resolve | Use Jaz Magic for documents |
208
+ | C | Create cash journal | Resolve | Bank fees, interest, charges |
209
+ | D | Flag for investigation | Resolve | Unexplained items |
210
+ | 4 | Re-check count | Verify | Should be zero (or timing items only) |
211
+ | 5 | Bank balance summary | Verify | Book balance = bank statement |
212
+ | 6 | Reconciliation report | Verify | Formal reconciliation statement |
213
+
214
+ ---
215
+
216
+ ## Tips for SMBs
217
+
218
+ **Do this weekly, not monthly.** A weekly 15-minute recon is far easier than a monthly 3-hour catch-up. Monday morning is ideal — reconcile the prior week's bank activity before the new week starts.
219
+
220
+ **Set up bank rules for recurring items.** If you pay the same rent, subscription, or utility every month, create a bank rule to auto-categorize it. This eliminates the most repetitive part of recon.
221
+
222
+ ```
223
+ POST /api/v1/bank-rules
224
+ ```
225
+
226
+ **Use bank feeds if available.** Aspire and Airwallex direct feeds auto-import bank records daily. This eliminates the CSV import step entirely.
227
+
228
+ **Don't let it pile up.** The longer a bank record sits unreconciled, the harder it is to figure out what it was. After 90 days, you're essentially doing forensic accounting. Stay current.
229
+
230
+ **Common SMB bank fee accounts:**
231
+ - Bank Charges / Bank Fees (operating expense)
232
+ - Interest Expense (for overdraft/loan interest)
233
+ - Interest Income (for savings/deposit interest)
234
+ - Foreign Exchange Gain/Loss (for FX conversion fees)
@@ -0,0 +1,135 @@
1
+ # Building Blocks for Accounting Jobs
2
+
3
+ Shared concepts that all jobs rely on. Read this first.
4
+
5
+ ---
6
+
7
+ ## Accounting Periods
8
+
9
+ Jaz uses a **financial year** (FY) that may not match the calendar year. The org's FY start date determines period boundaries.
10
+
11
+ **Period formats used in jobs:**
12
+ - Month: `YYYY-MM` (e.g., `2025-01` = January 2025)
13
+ - Quarter: `YYYY-QN` (e.g., `2025-Q1` = Jan–Mar 2025 for calendar-year orgs)
14
+ - Year: `YYYY` (e.g., `2025` = full FY 2025)
15
+
16
+ **Period boundaries matter for:**
17
+ - Search filters (`valueDate between`) — determines which transactions are "in period"
18
+ - Report snapshots (`startDate`, `endDate`, `primarySnapshotDate`) — determines what the reports cover
19
+ - Lock dates — determines what can no longer be edited
20
+
21
+ ---
22
+
23
+ ## Lock Dates
24
+
25
+ Lock dates prevent backdated entries. Two levels:
26
+
27
+ | Level | What it locks | When to set |
28
+ |-------|--------------|-------------|
29
+ | **Org-wide** | All transactions before this date | After month/quarter/year-end close |
30
+ | **Per-account** | Specific CoA account locked before date | For bank accounts after recon, or controlled accounts |
31
+
32
+ **Setting lock dates via API:**
33
+ - Org lock date: managed through organization settings
34
+ - Per-account lock date: `lockDate` field on CoA account
35
+
36
+ **Best practice for SMBs:**
37
+ - Set org lock date after completing each month-end close
38
+ - Move it forward each month: Jan close → lock to 2025-01-31, Feb close → lock to 2025-02-28
39
+ - Only move lock date forward, never backward (unless correcting errors — requires admin)
40
+
41
+ ---
42
+
43
+ ## Period Verification Pattern
44
+
45
+ Every job ends with a verification phase. The universal pattern:
46
+
47
+ ### 1. Trial Balance Check
48
+ ```
49
+ POST /generate-reports/trial-balance
50
+ { "startDate": "YYYY-MM-01", "endDate": "YYYY-MM-DD" }
51
+ ```
52
+ - Total debits MUST equal total credits
53
+ - No unexpected account balances (e.g., negative cash, negative inventory)
54
+ - Compare to prior period — flag significant variances
55
+
56
+ ### 2. P&L Review
57
+ ```
58
+ POST /generate-reports/profit-and-loss
59
+ { "primarySnapshotDate": "YYYY-MM-DD", "secondarySnapshotDate": "YYYY-MM-01" }
60
+ ```
61
+ - Revenue and expense trends should make sense
62
+ - One-off entries (accruals, adjustments) should be explainable
63
+
64
+ ### 3. Balance Sheet Review
65
+ ```
66
+ POST /generate-reports/balance-sheet
67
+ { "primarySnapshotDate": "YYYY-MM-DD" }
68
+ ```
69
+ - Assets = Liabilities + Equity (always, by definition)
70
+ - Bank balances match bank statements
71
+ - AR/AP aging ties to balance sheet control accounts
72
+
73
+ ### 4. Bank Balance Reconciliation
74
+ ```
75
+ POST /generate-reports/bank-balance-summary
76
+ { "primarySnapshotDate": "YYYY-MM-DD" }
77
+ ```
78
+ - Book balance per Jaz should match bank statement closing balance
79
+ - Differences = timing items (outstanding cheques, deposits in transit)
80
+
81
+ ---
82
+
83
+ ## Scheduler Verification
84
+
85
+ Many month-end steps are automated via schedulers. Before closing, verify:
86
+
87
+ 1. **Schedulers fired** — Check that recurring journals were created for the period
88
+ - `POST /journals/search` with capsule filter + valueDate in period
89
+ 2. **Amounts correct** — Fixed schedulers should produce consistent amounts
90
+ 3. **No duplicates** — If you manually posted a journal AND the scheduler fired, you'll double-count
91
+
92
+ **Common issue for SMBs:** Scheduler was set up mid-period or end date already passed. Always check before assuming automation handled it.
93
+
94
+ ---
95
+
96
+ ## Capsule Conventions for Jobs
97
+
98
+ Jobs reference capsules from transaction recipes. Standard capsule types:
99
+
100
+ | Capsule Type | Used By |
101
+ |-------------|---------|
102
+ | Prepaid Expenses | Prepaid amortization steps |
103
+ | Deferred Revenue | Revenue recognition steps |
104
+ | Accrued Expenses | Accrued expense steps |
105
+ | Loan Repayment | Loan interest accrual steps |
106
+ | Lease Accounting | IFRS 16 lease steps |
107
+ | Depreciation | Non-standard depreciation steps |
108
+ | FX Revaluation | Period-end FX revaluation |
109
+ | ECL Provision | Bad debt provision steps |
110
+ | Employee Benefits | Leave and bonus accrual steps |
111
+
112
+ **Verification shortcut:** Group the General Ledger by capsule to see the complete lifecycle of each multi-step workflow in one view.
113
+
114
+ ---
115
+
116
+ ## Report API Quick Reference
117
+
118
+ Jobs frequently generate reports. The key endpoints and their required fields:
119
+
120
+ | Report | Endpoint | Required Fields |
121
+ |--------|----------|----------------|
122
+ | Trial Balance | `POST /generate-reports/trial-balance` | `startDate`, `endDate` |
123
+ | P&L | `POST /generate-reports/profit-and-loss` | `primarySnapshotDate`, `secondarySnapshotDate` |
124
+ | Balance Sheet | `POST /generate-reports/balance-sheet` | `primarySnapshotDate` |
125
+ | General Ledger | `POST /generate-reports/general-ledger` | `startDate`, `endDate`, `groupBy: "ACCOUNT"` |
126
+ | AR Aging | `POST /generate-reports/ar-report` | `endDate` |
127
+ | AP Aging | `POST /generate-reports/ap-report` | `endDate` |
128
+ | Cash Balance | `POST /generate-reports/cash-balance` | `reportDate` |
129
+ | Cashflow | `POST /generate-reports/cashflow` | `primaryStartDate`, `primaryEndDate` |
130
+ | Bank Balance | `POST /generate-reports/bank-balance-summary` | `primarySnapshotDate` |
131
+ | Tax Ledger | `POST /generate-reports/vat-ledger` | `startDate`, `endDate` |
132
+ | FA Register | `POST /generate-reports/fixed-assets-summary` | (check endpoint) |
133
+ | Equity Movement | `POST /generate-reports/equity-movement` | `primarySnapshotStartDate`, `primarySnapshotEndDate` |
134
+
135
+ **Data exports** (Excel/CSV) use `/data-exports/` with the same report names but simpler field names (e.g., P&L export uses `startDate`/`endDate` instead of snapshot dates).
@@ -0,0 +1,273 @@
1
+ # Credit Control / AR Chase
2
+
3
+ Systematically chase overdue customer invoices, assess collection risk, and manage bad debt exposure. This is not just "send reminders" — it's a structured process to protect your cash flow and recognize when receivables are impaired.
4
+
5
+ **CLI:** `jaz jobs credit-control [--overdue-days 30] [--json]`
6
+
7
+ ---
8
+
9
+ ## Phase 1: Generate the AR Aging
10
+
11
+ The aging report is your starting point. Everything flows from this.
12
+
13
+ ### Step 1: Generate AR aging report
14
+
15
+ ```
16
+ POST /api/v1/generate-reports/ar-report
17
+ { "endDate": "2025-02-28" }
18
+ ```
19
+
20
+ **What you get:** All outstanding customer invoices grouped by aging bucket (current, 1-30 days, 31-60 days, 61-90 days, 91-120 days, 120+ days), with totals per customer and grand totals.
21
+
22
+ ### Step 2: Export for working paper (optional)
23
+
24
+ ```
25
+ POST /api/v1/data-exports/ar-report
26
+ { "endDate": "2025-02-28" }
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Phase 2: Prioritize
32
+
33
+ ### Step 3: Filter by overdue threshold
34
+
35
+ If `--overdue-days` is specified (e.g., 30), focus on invoices overdue by at least that many days. Otherwise, review all overdue items.
36
+
37
+ **Priority classification:**
38
+
39
+ | Priority | Overdue | Action |
40
+ |----------|---------|--------|
41
+ | **Critical** | 90+ days | Escalate to management, consider legal, assess bad debt |
42
+ | **High** | 60-90 days | Direct phone call, formal demand letter |
43
+ | **Medium** | 30-60 days | Follow-up email with statement of account |
44
+ | **Low** | 1-30 days | Gentle reminder, may be processing delay |
45
+ | **Current** | Not yet due | No action needed — monitor only |
46
+
47
+ ### Step 4: Group by customer, sort by largest balance
48
+
49
+ From the AR aging data, rank customers by total overdue amount (descending). The 80/20 rule applies — a handful of customers typically account for most of your overdue AR.
50
+
51
+ ---
52
+
53
+ ## Phase 3: Detailed Customer Review
54
+
55
+ For each overdue customer (starting with the largest balances), pull the full picture.
56
+
57
+ ### Step 5: List outstanding invoices for a customer
58
+
59
+ ```
60
+ POST /api/v1/invoices/search
61
+ {
62
+ "filter": {
63
+ "contactResourceId": { "eq": "<customer-uuid>" },
64
+ "status": { "eq": "POSTED" },
65
+ "balanceAmount": { "gt": 0 }
66
+ },
67
+ "sort": { "sortBy": ["dueDate"], "order": "ASC" },
68
+ "limit": 100
69
+ }
70
+ ```
71
+
72
+ **What to check per invoice:**
73
+ - `dueDate` — How overdue is it?
74
+ - `balanceAmount` — How much is still owed? (Could be partially paid)
75
+ - `reference` — The invoice number for follow-up correspondence
76
+ - `totalAmount` vs `balanceAmount` — Has the customer been making partial payments?
77
+
78
+ ### Step 6: Check for unapplied credit notes
79
+
80
+ Before chasing, verify there are no unapplied customer credit notes that should reduce the balance:
81
+
82
+ ```
83
+ POST /api/v1/customer-credit-notes/search
84
+ {
85
+ "filter": {
86
+ "contactResourceId": { "eq": "<customer-uuid>" },
87
+ "status": { "eq": "POSTED" }
88
+ },
89
+ "sort": { "sortBy": ["valueDate"], "order": "DESC" },
90
+ "limit": 50
91
+ }
92
+ ```
93
+
94
+ If there are unapplied credit notes, apply them before chasing:
95
+
96
+ ```
97
+ POST /api/v1/invoices/{invoiceResourceId}/credits
98
+ {
99
+ "credits": [
100
+ { "creditNoteResourceId": "<credit-note-uuid>", "amountApplied": 500.00 }
101
+ ]
102
+ }
103
+ ```
104
+
105
+ ### Step 7: Generate statement of account
106
+
107
+ ```
108
+ POST /api/v1/statement-of-account-export
109
+ ```
110
+
111
+ The statement of account is what you send to the customer — it shows all invoices, payments, and the running balance. Attach this to follow-up communications.
112
+
113
+ ---
114
+
115
+ ## Phase 4: Follow-Up Priority List
116
+
117
+ ### Step 8: Build the chase list
118
+
119
+ For each overdue customer, document:
120
+
121
+ | Customer | Total Overdue | Oldest Invoice | Days Overdue | Priority | Action |
122
+ |----------|--------------|----------------|--------------|----------|--------|
123
+ | Acme Corp | $45,000 | INV-1023 | 95 | Critical | Phone + demand letter |
124
+ | Beta Ltd | $12,500 | INV-1089 | 62 | High | Phone call |
125
+ | Gamma Inc | $3,200 | INV-1134 | 35 | Medium | Email reminder |
126
+
127
+ **Escalation process (typical SMB):**
128
+
129
+ 1. **Day 1-7 overdue:** Automated or gentle email reminder with invoice attached
130
+ 2. **Day 14 overdue:** Second reminder, direct email to AP contact
131
+ 3. **Day 30 overdue:** Phone call to AP contact, request payment commitment date
132
+ 4. **Day 45 overdue:** Escalate to customer's management, send statement of account
133
+ 5. **Day 60 overdue:** Formal demand letter, consider suspending future sales on credit
134
+ 6. **Day 90 overdue:** Final demand, engage collections agency or legal counsel
135
+ 7. **Day 120+ overdue:** Write off if uncollectable (see Phase 5)
136
+
137
+ ---
138
+
139
+ ## Phase 5: Bad Debt Assessment
140
+
141
+ **Conditional:** Only if there are material amounts in the 90+ day aging bucket.
142
+
143
+ ### Step 9: Assess bad debt risk
144
+
145
+ For invoices that appear uncollectable, evaluate using the ECL (Expected Credit Loss) model:
146
+
147
+ **Calculator:** `jaz calc ecl`
148
+
149
+ ```bash
150
+ jaz calc ecl --current 100000 --30d 50000 --60d 20000 --90d 10000 --120d 5000 --rates 0.5,2,5,10,50
151
+ ```
152
+
153
+ This produces the provision matrix — the estimated total bad debt exposure based on aging buckets and historical loss rates.
154
+
155
+ **Recipe:** `bad-debt-provision` — see `transaction-recipes/references/bad-debt-provision.md` for the full ECL provision pattern.
156
+
157
+ ### Step 10: Record bad debt write-off (if uncollectable)
158
+
159
+ When a specific invoice is confirmed uncollectable (customer bankrupt, dissolved, or dispute resolution failed), write it off:
160
+
161
+ **Option A: Customer credit note + write-off journal**
162
+
163
+ Create a customer credit note to clear the invoice balance:
164
+
165
+ ```
166
+ POST /api/v1/customer-credit-notes
167
+ {
168
+ "contactResourceId": "<customer-uuid>",
169
+ "saveAsDraft": false,
170
+ "reference": "CN-BADDEBT-001",
171
+ "valueDate": "2025-02-28",
172
+ "lineItems": [{
173
+ "name": "Bad debt write-off — INV-1023",
174
+ "unitPrice": 45000.00,
175
+ "quantity": 1,
176
+ "accountResourceId": "<bad-debt-expense-uuid>"
177
+ }]
178
+ }
179
+ ```
180
+
181
+ Then apply the credit note to the invoice:
182
+
183
+ ```
184
+ POST /api/v1/invoices/{invoiceResourceId}/credits
185
+ {
186
+ "credits": [
187
+ { "creditNoteResourceId": "<credit-note-uuid>", "amountApplied": 45000.00 }
188
+ ]
189
+ }
190
+ ```
191
+
192
+ **Option B: Use DEBT_WRITE_OFF payment method**
193
+
194
+ Record as a payment using the special write-off method:
195
+
196
+ ```
197
+ POST /api/v1/invoices/{invoiceResourceId}/payments
198
+ {
199
+ "payments": [{
200
+ "paymentAmount": 45000.00,
201
+ "transactionAmount": 45000.00,
202
+ "accountResourceId": "<bad-debt-expense-uuid>",
203
+ "paymentMethod": "DEBT_WRITE_OFF",
204
+ "reference": "WRITEOFF-INV-1023",
205
+ "valueDate": "2025-02-28"
206
+ }]
207
+ }
208
+ ```
209
+
210
+ **Accounting effect:** DR Bad Debt Expense, CR Accounts Receivable — removes the receivable from the books and recognizes the expense.
211
+
212
+ ---
213
+
214
+ ## Phase 6: Verification
215
+
216
+ ### Step 11: Re-run AR aging after actions
217
+
218
+ ```
219
+ POST /api/v1/generate-reports/ar-report
220
+ { "endDate": "2025-02-28" }
221
+ ```
222
+
223
+ **What to check:**
224
+ - Credit notes have reduced the correct invoice balances
225
+ - Written-off invoices no longer appear in the aging
226
+ - Total AR ties to the Accounts Receivable balance on the trial balance
227
+
228
+ ### Step 12: Review trial balance impact
229
+
230
+ ```
231
+ POST /api/v1/generate-reports/trial-balance
232
+ { "startDate": "2025-02-01", "endDate": "2025-02-28" }
233
+ ```
234
+
235
+ **What to check:**
236
+ - Accounts Receivable balance reflects all collections, credit notes, and write-offs
237
+ - Bad Debt Expense (if write-offs were made) shows the correct amount
238
+ - Allowance for Doubtful Debts (if using provision method) reflects the ECL calculation
239
+
240
+ ---
241
+
242
+ ## Credit Control Checklist (Quick Reference)
243
+
244
+ | # | Step | Phase | Conditional |
245
+ |---|------|-------|-------------|
246
+ | 1 | Generate AR aging | Assess | Always |
247
+ | 2 | Export working paper | Assess | Optional |
248
+ | 3 | Filter by overdue threshold | Prioritize | If --overdue-days specified |
249
+ | 4 | Group by customer | Prioritize | Always |
250
+ | 5 | List outstanding invoices | Review | Always |
251
+ | 6 | Check unapplied credit notes | Review | Always |
252
+ | 7 | Generate statement of account | Review | Always |
253
+ | 8 | Build chase list | Follow-up | Always |
254
+ | 9 | Assess bad debt (ECL) | Bad debt | If material 90d+ balances |
255
+ | 10 | Record write-off | Bad debt | If confirmed uncollectable |
256
+ | 11 | Re-run AR aging | Verify | Always |
257
+ | 12 | Review trial balance | Verify | Always |
258
+
259
+ ---
260
+
261
+ ## Tips for SMBs
262
+
263
+ **Typical credit terms:** Net 30 is standard in Singapore. Some industries use Net 60 or Net 14. Whatever your terms, enforce them consistently — if you let one customer pay at 60 when terms are 30, everyone will.
264
+
265
+ **Prevention is cheaper than collection.** Before extending credit to a new customer, do a basic credit check (ACRA business profile for SG companies, $5.50). Set a credit limit and stick to it.
266
+
267
+ **The phone is more effective than email.** After 30 days, email follow-ups have diminishing returns. A 5-minute phone call to the AP department resolves more overdue invoices than 10 emails.
268
+
269
+ **Document everything.** Keep records of all follow-up attempts (dates, who you spoke to, commitments made). If it goes to legal, you need an evidence trail.
270
+
271
+ **When to involve legal:** If the amount exceeds $20,000 and the customer is unresponsive after 90 days, consider a letter of demand from a lawyer ($300-500). For amounts under $10,000, the Small Claims Tribunal (SG) is a cost-effective option.
272
+
273
+ **Bad debt tax deduction (SG):** Bad debts written off are deductible for income tax purposes if you can prove the debt is genuinely irrecoverable and reasonable steps were taken to collect. Keep documentation.