jaz-clio 4.30.10 → 4.30.12

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/README.md CHANGED
@@ -235,7 +235,7 @@ Every command supports `--json` for structured output — ideal for piping to ot
235
235
 
236
236
  ## MCP Server
237
237
 
238
- Expose all 205 CLI tools to AI coding and coworking agents via the Model Context Protocol (MCP). The server runs locally on your machine — no cloud, no ports. API calls go directly from your machine to the Jaz API.
238
+ Expose all 207 CLI tools to AI coding and coworking agents via the Model Context Protocol (MCP). The server runs locally on your machine — no cloud, no ports. API calls go directly from your machine to the Jaz API.
239
239
 
240
240
  **Claude Code:**
241
241
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-api
3
- version: 4.30.10
3
+ version: 4.30.12
4
4
  description: Complete reference for the Jaz REST API — the accounting platform backend. Use this skill whenever building, modifying, debugging, or extending any code that calls the API — including API clients, integrations, data seeding, test data, or new endpoint work. Contains every field name, response shape, error, gotcha, and edge case discovered through live production testing.
5
5
  license: MIT
6
6
  compatibility: Requires Jaz API key (x-jk-api-key header). Works with Claude Code, Google Antigravity, OpenAI Codex, GitHub Copilot, Cursor, and any agent that reads markdown.
@@ -278,6 +278,9 @@ Bills, invoices, and credit notes share identical mandatory field specs. Adding
278
278
  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.
279
279
  106. **Contact PUT uses `email` (string), not `emails` (array)** — GET returns `emails: [{email, label}]` (array) but PUT accepts `email: "user@example.com"` (string). Sending the `emails` array in PUT body causes 400 "Invalid request body". The CLI and tool executor handle this automatically via read-modify-write with the correct field.
280
280
 
281
+ ### Quick Fix (Bulk Update)
282
+ 107. **20 Quick Fix endpoints for bulk-updating transactions and line items** — `POST /api/v1/quick-fix/{entity}` with `{ resourceIds: [...], attributes: {...} }`. Response: `{ updated: [...], failed: [{ resourceId, error, errorCode }] }`. Entities grouped by domain: **ARAP**: invoices, bills, customer-credit-notes, supplier-credit-notes. **Accounting**: journals, cash-entries. **Schedulers**: sale-schedules, purchase-schedules, subscription-schedules, journal-schedules. Line-item endpoints add `/line-items` suffix. ARAP line items use `{ lineItemResourceIds, attributes }`. Scheduler line items use `{ schedulerUpdates: [{ schedulerResourceId, lineItemUpdates }] }`. **Known gotcha**: `valueDate` (and `dueDate` for ARAP) must currently be included in `attributes` even when unchanged — absent fields are treated as "remove" rather than "keep existing". This will be fixed server-side.
283
+
281
284
  ## Supporting Files
282
285
 
283
286
  For detailed reference, read these files in this skill directory:
@@ -1814,4 +1814,93 @@ Middleware on payment, credit, and refund endpoints automatically wraps a flat J
1814
1814
 
1815
1815
  ---
1816
1816
 
1817
- *Last updated: 2026-02-23 — Added: Account single create (POST /chart-of-accounts) and delete (DELETE /chart-of-accounts/:id). Currency list: added customRateCount field, field name gotcha (currencyCode NOT code). Currency enable: 400 on duplicate, one-way operation. Currency rate POST: string response gotcha (no resourceId returned).*
1817
+ ---
1818
+
1819
+ ## 17. Quick Fix (Bulk Update)
1820
+
1821
+ 20 endpoints for bulk-updating transactions and line items in a single API call.
1822
+
1823
+ ### Pattern
1824
+
1825
+ ```
1826
+ POST /api/v1/quick-fix/{entity}
1827
+ POST /api/v1/quick-fix/{entity}/line-items
1828
+ ```
1829
+
1830
+ ### Entities (grouped by domain)
1831
+
1832
+ **ARAP**: `invoices`, `bills`, `customer-credit-notes`, `supplier-credit-notes`
1833
+ **Accounting**: `journals`, `cash-entries`
1834
+ **Schedulers**: `sale-schedules`, `purchase-schedules`, `subscription-schedules`, `journal-schedules`
1835
+
1836
+ ### Transaction-Level Request
1837
+
1838
+ ```json
1839
+ POST /api/v1/quick-fix/bills
1840
+ {
1841
+ "resourceIds": ["uuid1", "uuid2"],
1842
+ "attributes": {
1843
+ "valueDate": "2026-03-01",
1844
+ "dueDate": "2026-03-31",
1845
+ "tags": ["Q1-2026"],
1846
+ "contactResourceId": "uuid"
1847
+ }
1848
+ }
1849
+ ```
1850
+
1851
+ ### Line-Item-Level Request (ARAP + Accounting)
1852
+
1853
+ ```json
1854
+ POST /api/v1/quick-fix/invoices/line-items
1855
+ {
1856
+ "lineItemResourceIds": ["li-uuid1", "li-uuid2"],
1857
+ "attributes": {
1858
+ "name": "Updated Item",
1859
+ "quantity": 2,
1860
+ "unitPrice": 150,
1861
+ "organizationAccountResourceId": "acct-uuid",
1862
+ "taxProfileResourceId": "tax-uuid"
1863
+ }
1864
+ }
1865
+ ```
1866
+
1867
+ ### Line-Item-Level Request (Schedulers)
1868
+
1869
+ ```json
1870
+ POST /api/v1/quick-fix/sale-schedules/line-items
1871
+ {
1872
+ "schedulerUpdates": [
1873
+ {
1874
+ "schedulerResourceId": "sched-uuid",
1875
+ "lineItemUpdates": [
1876
+ { "arrayIndex": 0, "unitPrice": 200 }
1877
+ ]
1878
+ }
1879
+ ]
1880
+ }
1881
+ ```
1882
+
1883
+ ### Response (all 20 endpoints)
1884
+
1885
+ ```json
1886
+ {
1887
+ "updated": ["uuid1", "uuid2"],
1888
+ "failed": [
1889
+ { "resourceId": "uuid3", "error": "Transaction is locked", "errorCode": "TRANSACTION_LOCKED" }
1890
+ ]
1891
+ }
1892
+ ```
1893
+
1894
+ ### Updatable Fields
1895
+
1896
+ **Transaction-level**: valueDate, dueDate (ARAP), contactResourceId, tags, capsuleResourceId, customFields, currencySettings, taxCurrencySettings, invoiceNotes (invoices/CNs), templateResourceId (invoices/CNs), billFrom/billTo (invoices/CNs), endDate/interval (schedulers).
1897
+
1898
+ **ARAP line items**: name, quantity, unit, unitPrice, discount, itemResourceId, organizationAccountResourceId, taxProfileResourceId, classifierConfig, withholdingTax (bills/supplier-CNs only).
1899
+
1900
+ **Journal/cash-entry line items**: organizationAccountResourceId, amount, description, taxProfileResourceId, classifierConfig.
1901
+
1902
+ **Known gotcha**: `valueDate` (and `dueDate` for ARAP) must currently be included in `attributes` even when unchanged — absent fields are treated as "remove". Server-side fix pending.
1903
+
1904
+ ---
1905
+
1906
+ *Last updated: 2026-03-09 — Added: Quick Fix (20 bulk-update endpoints), subscription CRUD (proratedConfig, PUT cancel).*
@@ -819,4 +819,18 @@ Journals support a top-level `currency` object to create entries in a foreign cu
819
819
 
820
820
  ---
821
821
 
822
- *Last updated: 2026-03-09 — Added cash entry PUT 500 (missing accountResourceId), contact PUT email/emails asymmetry, tax profile dedup/scoping, journal balance check, duplicate reference errors.*
822
+ ### Quick Fix Errors
823
+
824
+ **"Not allowed to remove valueDate of a sale/purchase/journal"** — `valueDate` absent from `attributes`. Currently must be included even if unchanged. Server-side fix pending.
825
+
826
+ **"Not allowed to remove dueDate of a sale"** — Same pattern for `dueDate` on invoices.
827
+
828
+ **"Not allowed to remove pdfTemplate of a sale"** — Same pattern for `templateResourceId` on invoices that have a template.
829
+
830
+ **"Item name is required to bulk update purchase item details"** — Line-item quick-fix requires `name` in attributes. Same "absent = remove" pattern.
831
+
832
+ **"TRANSACTION_LOCKED"** — Transaction is in a locked period. Cannot update.
833
+
834
+ ---
835
+
836
+ *Last updated: 2026-03-09 — Added Quick Fix errors (absent = remove gotcha), cash entry PUT 500 (missing accountResourceId), contact PUT email/emails asymmetry.*
@@ -237,6 +237,12 @@ Bank statement import supports CSV and PDF with configurable column mapping. Sta
237
237
 
238
238
  **API**: `POST /magic/importBankStatementFromAttachment` (multipart: `sourceFile`, `accountResourceId`, `businessTransactionType: "BANK_STATEMENT"`, `sourceType: "FILE"`)
239
239
 
240
+ ### Quick Fix (Bulk Update)
241
+
242
+ Mass-edit transactions and line items in a single operation. Replaces the need to open and update each transaction individually. Supports all transaction types (invoices, bills, credit notes, journals, cash entries) and their scheduled/subscription variants. Common use cases: batch date corrections, reassigning contacts, bulk-tagging for reporting, changing accounts/tax profiles across multiple line items.
243
+
244
+ **API**: `POST /api/v1/quick-fix/{entity}` (transaction-level) + `POST /api/v1/quick-fix/{entity}/line-items` (line-item-level). 20 endpoints total.
245
+
240
246
  ---
241
247
 
242
248
  *Maintained alongside [help.jaz.ai](https://help.jaz.ai).*
@@ -565,4 +565,15 @@ Battle-tested patterns from production Jaz API clients:
565
565
 
566
566
  ---
567
567
 
568
- *Last updated: 2026-02-23 — Added: Currency response field mapping (currencyCode NOT code, currencyName NOT name, currencySymbol NOT symbol, customRateCount). CurrencyRate response field mapping (sourceCurrencyCode, functionalCurrencyCode, notes). Account create field mapping (classificationType, currency, foreign-currency accounts). Response shape quirks: rate POST/PUT return plain strings.*
568
+ ### Quick Fix (Bulk Update) Field Mapping
569
+
570
+ | What you'd guess | Actual field | Notes |
571
+ |-------------------|-------------|-------|
572
+ | `accountResourceId` (line items) | `organizationAccountResourceId` | Quick-fix line items use GET-side field name, NOT the POST alias |
573
+ | `repeat` (schedulers) | `interval` | Quick-fix scheduler attributes use `interval`, NOT `repeat` |
574
+ | `lineItems` | `lineItemResourceIds` | Pass individual line item IDs, not the transaction resourceId |
575
+ | `schedulerResourceId` | `schedulerResourceId` | For scheduler line-item updates (in `schedulerUpdates` array) |
576
+
577
+ ---
578
+
579
+ *Last updated: 2026-03-09 — Added Quick Fix field mapping. Previous: Currency response fields, account create fields.*
@@ -694,6 +694,17 @@ These features exist in the Jaz platform and may affect API responses or cause u
694
694
  - Move transactions between capsules via `POST /api/v1/moveTransactionCapsules`
695
695
  - Search transactions within capsules
696
696
 
697
+ ### Quick Fix (Bulk Update) — 20 Endpoints
698
+
699
+ Bulk-update transactions or line items in a single call. Pattern: `POST /api/v1/quick-fix/{entity}` + `POST /api/v1/quick-fix/{entity}/line-items`.
700
+
701
+ **ARAP**: `invoices`, `bills`, `customer-credit-notes`, `supplier-credit-notes` (× 2 = 8)
702
+ **Accounting**: `journals`, `cash-entries` (× 2 = 4)
703
+ **Schedulers**: `sale-schedules`, `purchase-schedules`, `subscription-schedules`, `journal-schedules` (× 2 = 8)
704
+
705
+ Request: `{ resourceIds: [...], attributes: {...} }` (transactions) or `{ lineItemResourceIds: [...], attributes: {...} }` (line items) or `{ schedulerUpdates: [...] }` (scheduler line items).
706
+ Response: `{ updated: [...], failed: [{ resourceId, error, errorCode }] }`.
707
+
697
708
  ---
698
709
 
699
- *Last updated: 2026-02-14 — All search/list responses standardized to flat shape (no outer data wrapper). Kebab-case aliases for capsule-types and move-transaction-capsules. Sort now array on all endpoints (no exceptions). Major overhaul: Added 20+ missing endpoints (bank rules, capsule types, nano classifiers, catalogs, reference data, auto-reconciliation). Expanded search filter syntax with all 7 operator types, nested filters, logical operators, andGroup/orGroup, date format asymmetry. Added cross-reference to search-reference.md. All data sourced from Go structs.*
710
+ *Last updated: 2026-03-09Added 20 Quick Fix endpoints (bulk update). Previous: All search/list responses standardized to flat shape, kebab-case aliases, sort array on all endpoints.*
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-conversion
3
- version: 4.30.10
3
+ version: 4.30.12
4
4
  description: Accounting data conversion skill — migrates customer data from Xero, QuickBooks, Sage, MYOB, and Excel exports to Jaz. Covers config, quick, and full conversion workflows, Excel parsing, CoA/contact/tax/items mapping, clearing accounts, TTB, and TB verification.
5
5
  ---
6
6
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-jobs
3
- version: 4.30.10
3
+ version: 4.30.12
4
4
  description: 12 accounting jobs for SMB bookkeepers and accountants — month-end, quarter-end, and year-end close playbooks plus 9 ad-hoc operational jobs (bank recon, document collection, GST/VAT filing, payment runs, credit control, supplier recon, audit prep, fixed asset review, statutory filing). Jobs can have paired tools as nested subcommands (e.g., `clio jobs bank-recon match`, `clio jobs document-collection ingest`, `clio jobs statutory-filing sg-cs`). Paired with an interactive CLI blueprint generator (clio jobs).
5
5
  license: MIT
6
6
  compatibility: Works with Claude Code, Claude Cowork, Claude.ai, and any agent that reads markdown. For API payloads, load the jaz-api skill. For individual transaction patterns, load the jaz-recipes skill.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 4.30.10
3
+ version: 4.30.12
4
4
  description: 16 IFRS-compliant recipes for complex multi-step accounting in Jaz — prepaid amortization, deferred revenue, loan schedules, IFRS 16 leases, hire purchase, fixed deposits, asset disposal, FX revaluation, ECL provisioning, IAS 37 provisions, dividends, intercompany, and capital WIP. Each recipe includes journal entries, capsule structure, and verification steps. Paired with 13 financial calculators that produce execution-ready blueprints with workings.
5
5
  license: MIT
6
6
  compatibility: Works with Claude Code, Claude Cowork, Claude.ai, and any agent that reads markdown. For API payloads, load the jaz-api skill alongside this one.
@@ -0,0 +1,139 @@
1
+ import chalk from 'chalk';
2
+ import { readFileSync } from 'node:fs';
3
+ import { quickFix, quickFixLineItems, QUICK_FIX_ENTITIES } from '../core/api/quick-fix.js';
4
+ import { QUICK_FIX_ARAP } from '../core/api/quick-fix.js';
5
+ import { apiAction } from './api-action.js';
6
+ function parseJson(source, label) {
7
+ try {
8
+ return JSON.parse(source);
9
+ }
10
+ catch (err) {
11
+ console.error(chalk.red(`Invalid JSON in ${label}: ${err.message}`));
12
+ process.exitCode = 1;
13
+ return null;
14
+ }
15
+ }
16
+ export function registerQuickFixCommand(program) {
17
+ const cmd = program
18
+ .command('quick-fix <entity>')
19
+ .description('Bulk-update transactions or line items in one call')
20
+ .addHelpText('after', `
21
+ Entities (grouped by domain):
22
+ ARAP: invoices, bills, customer-credit-notes, supplier-credit-notes
23
+ Accounting: journals, cash-entries
24
+ Schedulers: sale-schedules, purchase-schedules, subscription-schedules, journal-schedules
25
+
26
+ Examples:
27
+ clio quick-fix invoices --ids id1,id2 --attributes '{"valueDate":"2026-01-15","tags":["Q1"]}'
28
+ clio quick-fix bills --ids id1 --date 2026-02-01 --due 2026-03-01 --tag Marketing
29
+ clio quick-fix journals --line-items --ids li1,li2 --attributes '{"organizationAccountResourceId":"<uuid>"}'
30
+ clio quick-fix sale-schedules --line-items --input scheduler-updates.json`)
31
+ .option('--ids <csv>', 'Comma-separated resourceIds (transaction or line item)')
32
+ .option('--line-items', 'Target line items instead of transactions')
33
+ .option('--attributes <json>', 'Attributes JSON object')
34
+ .option('--input <file>', 'Read attributes/body from JSON file')
35
+ .option('--date <date>', 'Shorthand: set valueDate (YYYY-MM-DD)')
36
+ .option('--due <date>', 'Shorthand: set dueDate (YYYY-MM-DD)')
37
+ .option('--tag <name>', 'Shorthand: set tags to [name]')
38
+ .option('--contact <id>', 'Shorthand: set contactResourceId')
39
+ .option('--account <id>', 'Shorthand: set organizationAccountResourceId (line items)')
40
+ .option('--tax-profile <id>', 'Shorthand: set taxProfileResourceId (line items)')
41
+ .option('--api-key <key>', 'API key')
42
+ .option('--json', 'JSON output')
43
+ .action((entity, opts) => apiAction(async (client) => {
44
+ // ── Validate entity ──────────────────────────────────────
45
+ if (!QUICK_FIX_ENTITIES.includes(entity)) {
46
+ console.error(chalk.red(`Unknown entity: ${entity}`));
47
+ console.error(`Valid entities: ${QUICK_FIX_ENTITIES.join(', ')}`);
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+ // ── Build body ───────────────────────────────────────────
52
+ if (opts.input) {
53
+ const raw = parseJson(readFileSync(opts.input, 'utf-8'), '--input');
54
+ if (!raw)
55
+ return;
56
+ const result = opts.lineItems
57
+ ? await quickFixLineItems(client, entity, raw)
58
+ : await quickFix(client, entity, raw);
59
+ formatResult(result, opts.json);
60
+ return;
61
+ }
62
+ const ids = opts.ids ? opts.ids.split(',').map((s) => s.trim()).filter(Boolean) : [];
63
+ if (ids.length === 0) {
64
+ console.error(chalk.red('--ids is required (comma-separated resourceIds)'));
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ // Merge --attributes JSON with shorthand flags
69
+ let attrs = {};
70
+ if (opts.attributes) {
71
+ const parsed = parseJson(opts.attributes, '--attributes');
72
+ if (!parsed)
73
+ return;
74
+ attrs = parsed;
75
+ }
76
+ if (opts.date)
77
+ attrs.valueDate = opts.date;
78
+ if (opts.due)
79
+ attrs.dueDate = opts.due;
80
+ if (opts.tag)
81
+ attrs.tags = [opts.tag];
82
+ if (opts.contact)
83
+ attrs.contactResourceId = opts.contact;
84
+ if (opts.account)
85
+ attrs.organizationAccountResourceId = opts.account;
86
+ if (opts.taxProfile)
87
+ attrs.taxProfileResourceId = opts.taxProfile;
88
+ // ── Pre-flight: require valueDate/dueDate (API treats absent as remove) ──
89
+ if (!opts.lineItems) {
90
+ if (!('valueDate' in attrs)) {
91
+ console.error(chalk.red('valueDate is required in attributes (use --date or include in --attributes)'));
92
+ console.error(chalk.dim('The API currently treats absent fields as "remove". Server-side fix pending.'));
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ if (QUICK_FIX_ARAP.includes(entity) && !('dueDate' in attrs)) {
97
+ console.error(chalk.red('dueDate is required for ARAP entities (use --due or include in --attributes)'));
98
+ console.error(chalk.dim('The API currently treats absent fields as "remove". Server-side fix pending.'));
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ }
103
+ if (opts.lineItems) {
104
+ const result = await quickFixLineItems(client, entity, {
105
+ lineItemResourceIds: ids,
106
+ attributes: attrs,
107
+ });
108
+ formatResult(result, opts.json);
109
+ }
110
+ else {
111
+ const result = await quickFix(client, entity, {
112
+ resourceIds: ids,
113
+ attributes: attrs,
114
+ });
115
+ formatResult(result, opts.json);
116
+ }
117
+ })(opts));
118
+ }
119
+ function formatResult(result, json) {
120
+ if (json) {
121
+ console.log(JSON.stringify(result, null, 2));
122
+ return;
123
+ }
124
+ if (result.updated.length > 0) {
125
+ console.log(chalk.green(`Updated ${result.updated.length} item(s):`));
126
+ for (const id of result.updated)
127
+ console.log(` ${chalk.cyan(id)}`);
128
+ }
129
+ if (result.failed.length > 0) {
130
+ console.log(chalk.red(`Failed ${result.failed.length} item(s):`));
131
+ for (const f of result.failed) {
132
+ console.log(` ${chalk.cyan(f.resourceId)} ${chalk.red(f.error)}${f.errorCode ? ` (${f.errorCode})` : ''}`);
133
+ }
134
+ process.exitCode = 1;
135
+ }
136
+ if (result.updated.length === 0 && result.failed.length === 0) {
137
+ console.log('No items processed.');
138
+ }
139
+ }
@@ -33,5 +33,6 @@ export * as subscriptions from './subscriptions.js';
33
33
  export * as contactGroups from './contact-groups.js';
34
34
  export * as inventory from './inventory.js';
35
35
  export * as search from './search.js';
36
+ export * as quickFix from './quick-fix.js';
36
37
  // ── Guards (pre-flight checks for create operations) ────────────
37
38
  export * from './guards.js';
@@ -0,0 +1,16 @@
1
+ // ── Entity Groups ────────────────────────────────────────────────
2
+ // Grouped by domain — values are API path segments for /api/v1/quick-fix/{entity}
3
+ export const QUICK_FIX_ARAP = ['invoices', 'bills', 'customer-credit-notes', 'supplier-credit-notes'];
4
+ const QUICK_FIX_ACCOUNTING = ['journals', 'cash-entries'];
5
+ const QUICK_FIX_SCHEDULERS = ['sale-schedules', 'purchase-schedules', 'subscription-schedules', 'journal-schedules'];
6
+ export const QUICK_FIX_ENTITIES = [...QUICK_FIX_ARAP, ...QUICK_FIX_ACCOUNTING, ...QUICK_FIX_SCHEDULERS];
7
+ // ── Transaction-Level Quick Fix ──────────────────────────────────
8
+ export async function quickFix(client, entity, body) {
9
+ return client.post(`/api/v1/quick-fix/${entity}`, body);
10
+ }
11
+ // ── Line-Item-Level Quick Fix ────────────────────────────────────
12
+ // ARAP: { lineItemResourceIds: string[], attributes: {...} }
13
+ // Schedulers: { schedulerUpdates: [{ schedulerResourceId, lineItemUpdates: [...] }] }
14
+ export async function quickFixLineItems(client, entity, body) {
15
+ return client.post(`/api/v1/quick-fix/${entity}/line-items`, body);
16
+ }
@@ -125,6 +125,12 @@ export const TOOL_NAMESPACES = [
125
125
  description: 'Payments search/list across all transaction types. Cashflow transaction ledger. Universal cross-entity search. Transaction summary (fetch any transaction + attachments + payment history in one call).',
126
126
  groups: ['payments', 'cashflow', 'search'],
127
127
  },
128
+ // ── Quick Fix (Bulk Update) ────────────────────────────────
129
+ {
130
+ name: 'quick_fix',
131
+ description: 'Quick Fix: bulk-update multiple transactions or line items in one call. Change dates, contacts, tags, accounts, tax profiles, custom fields across many invoices/bills/journals/credit-notes/cash-entries/schedulers at once. Also: batch update, mass edit.',
132
+ groups: ['quick_fix'],
133
+ },
128
134
  // ── Drafts ──────────────────────────────────────────────────
129
135
  {
130
136
  name: 'drafts',
@@ -39,6 +39,7 @@ import { listContactGroups, getContactGroup, searchContactGroups, createContactG
39
39
  import { listInventoryItems, getInventoryBalance } from '../api/inventory.js';
40
40
  import { universalSearch } from '../api/search.js';
41
41
  import { listCustomFields, getCustomField, searchCustomFields, createCustomField, updateCustomField, deleteCustomField } from '../api/custom-fields.js';
42
+ import { quickFix, quickFixLineItems, QUICK_FIX_ENTITIES } from '../api/quick-fix.js';
42
43
  // Job blueprints (offline — no API calls)
43
44
  import { generateMonthEndBlueprint } from '../jobs/month-end/blueprint.js';
44
45
  import { generateQuarterEndBlueprint } from '../jobs/quarter-end/blueprint.js';
@@ -652,6 +653,18 @@ export const TOOL_DEFINITIONS = [
652
653
  execute: async (ctx, input) => {
653
654
  const { resourceId: rid, ...overrides } = input;
654
655
  const merged = await fetchAndMerge(ctx.client, 'invoice', rid, overrides);
656
+ // Dedup guard: if reference already exists on another invoice, auto-suffix to avoid 422
657
+ if (merged.reference) {
658
+ const ref = merged.reference;
659
+ const existing = await searchInvoices(ctx.client, {
660
+ filter: { reference: { eq: ref } }, limit: 1, offset: 0,
661
+ sort: { sortBy: ['valueDate'], order: 'DESC' },
662
+ });
663
+ const dupes = (existing.data ?? []).filter((inv) => inv.resourceId !== rid);
664
+ if (dupes.length > 0) {
665
+ merged.reference = `${ref}-${Date.now() % 10000}`;
666
+ }
667
+ }
655
668
  return finalizeInvoice(ctx.client, rid, merged);
656
669
  },
657
670
  },
@@ -1792,8 +1805,8 @@ Steps: 1) search_customer_credit_notes with status UNAPPLIED for the same contac
1792
1805
  WHEN TO USE: customer payments received, refunds from suppliers, insurance payouts, external deposits.
1793
1806
  WHEN NOT TO USE: moving money between your own bank/cash accounts — use create_cash_transfer instead.
1794
1807
  - accountResourceId MUST be a Bank Accounts type account — use list_bank_accounts or search_accounts with accountType "Bank Accounts" to find the correct one. Non-bank accounts are rejected.
1795
- - journalEntries are the offsetting entries (e.g., revenue account). Each needs accountResourceId, type (DEBIT/CREDIT), and amount.
1796
- - The API enforces account separation: cash-in accounts cannot be used for cash-out.`,
1808
+ - journalEntries are the offsetting entries. Each needs accountResourceId, type (DEBIT/CREDIT), and amount. IMPORTANT: offset accounts must be regular P&L or balance sheet accounts (expense, revenue, asset, liability) — NOT bank/cash accounts or controlled accounts (AR/AP). Example: Service Revenue, Interest Income, Other Income.
1809
+ - The API enforces account separation: cash-in bank account cannot appear in journalEntries.`,
1797
1810
  params: {
1798
1811
  reference: { type: 'string', description: 'Reference number' },
1799
1812
  valueDate: { type: 'string', description: 'Date (YYYY-MM-DD)' },
@@ -1821,8 +1834,8 @@ WHEN NOT TO USE: moving money between your own bank/cash accounts — use create
1821
1834
  WHEN TO USE: expenses paid, supplier payments, reimbursements, withdrawals to external parties.
1822
1835
  WHEN NOT TO USE: moving money between your own bank/cash accounts — use create_cash_transfer instead.
1823
1836
  - accountResourceId MUST be a Bank Accounts type account — use list_bank_accounts or search_accounts with accountType "Bank Accounts" to find the correct one. Non-bank accounts are rejected.
1824
- - journalEntries are the offsetting entries (e.g., expense account). Each needs accountResourceId, type (DEBIT/CREDIT), and amount.
1825
- - The API enforces account separation: cash-out accounts cannot be used for cash-in.`,
1837
+ - journalEntries are the offsetting entries. Each needs accountResourceId, type (DEBIT/CREDIT), and amount. IMPORTANT: offset accounts must be regular P&L or balance sheet accounts (expense, revenue, asset, liability) — NOT bank/cash accounts or controlled accounts (AR/AP). Example: Utilities Expense, Office Supplies, Service Revenue.
1838
+ - The API enforces account separation: cash-out bank account cannot appear in journalEntries.`,
1826
1839
  params: {
1827
1840
  reference: { type: 'string', description: 'Reference number' },
1828
1841
  valueDate: { type: 'string', description: 'Date (YYYY-MM-DD)' },
@@ -1871,7 +1884,7 @@ WHEN NOT TO USE: moving money between your own bank/cash accounts — use create
1871
1884
  readOnly: false,
1872
1885
  execute: async (ctx, input) => {
1873
1886
  const { resourceId: rid, ...data } = input;
1874
- return updateCashIn(ctx.client, rid, { ...data, resourceId: rid });
1887
+ return updateCashIn(ctx.client, rid, data);
1875
1888
  },
1876
1889
  },
1877
1890
  {
@@ -1902,7 +1915,7 @@ WHEN NOT TO USE: moving money between your own bank/cash accounts — use create
1902
1915
  readOnly: false,
1903
1916
  execute: async (ctx, input) => {
1904
1917
  const { resourceId: rid, ...data } = input;
1905
- return updateCashOut(ctx.client, rid, { ...data, resourceId: rid });
1918
+ return updateCashOut(ctx.client, rid, data);
1906
1919
  },
1907
1920
  },
1908
1921
  // ── Cash Transfers ─────────────────────────────────────────────
@@ -2236,7 +2249,8 @@ Available export types: trial-balance, balance-sheet, profit-and-loss, general-l
2236
2249
  // ── Recipes ───────────────────────────────────────────────────
2237
2250
  {
2238
2251
  name: 'plan_recipe',
2239
- description: `Plan a transaction recipe — run a financial calculator and show what accounts, contacts, and bank accounts are needed. This is READ-ONLY (no API calls, no transactions created). To actually create the transactions, call execute_recipe.
2252
+ description: `Plan a transaction recipe — run a financial calculator and show what accounts, contacts, and bank accounts are needed. This is READ-ONLY (no API calls, no transactions created).
2253
+ After planning, ALWAYS use execute_recipe to create all transactions in one call — do NOT manually create journals/invoices/bills.
2240
2254
  Supported recipes: ${RECIPE_TYPES.join(', ')}
2241
2255
  Returns: capsule type/name, required accounts, step breakdown (journal/bill/invoice/cash-in/cash-out), and full calculator results.
2242
2256
  Use this BEFORE execute_recipe to verify requirements. Parameters vary by recipe — see recipe skill docs for per-recipe params.
@@ -2294,8 +2308,8 @@ CRITICAL: ALWAYS call this tool for ANY calculation involving: depreciation, amo
2294
2308
  },
2295
2309
  {
2296
2310
  name: 'execute_recipe',
2297
- description: `Execute a transaction recipe end-to-end — run calculator, create capsule, post all entries.
2298
- Replaces ~20 manual tool calls with 1 call. Use plan_recipe first to verify requirements.
2311
+ description: `Execute a transaction recipe end-to-end — run calculator, create capsule, post all entries in one call.
2312
+ PREFERRED over manual transaction creation — replaces ~20 manual tool calls. After plan_recipe, ALWAYS use this tool (not create_journal/create_invoice/create_cash_out).
2299
2313
  Supported recipes: ${RECIPE_TYPES.join(', ')}
2300
2314
  Requires startDate (to generate blueprint with dated steps).
2301
2315
  Auto-resolves accounts from chart of accounts. Provide bankAccountName for recipes with cash-in/cash-out steps, contactName for recipes with invoice/bill steps.`,
@@ -3064,14 +3078,15 @@ CRITICAL:
3064
3078
  {
3065
3079
  name: 'create_bank_rule',
3066
3080
  description: `Create a bank reconciliation rule. Rules auto-match bank records to transactions during reconciliation.
3067
- - actionType: "RECONCILE_WITH_DIRECT_CASH_ENTRY" (most common)
3081
+ - actionType: "RECONCILE_WITH_DIRECT_CASH_ENTRY" (most common — creates cash-in/cash-out on match)
3068
3082
  - appliesToReconciliationAccountResourceId: the bank account this rule applies to
3069
- - configuration: allocation settings (fixed amounts, percentages, accounts, tax)`,
3083
+ - configuration MUST include: allocationType ("PERCENTAGE" or "FIXED"), allocationDetails array with organizationAccountResourceId + percentage (or fixedAmount) + optional taxProfileResourceId
3084
+ Example configuration: { "allocationType": "PERCENTAGE", "allocationDetails": [{ "organizationAccountResourceId": "<revenue-account-id>", "percentage": 100 }] }`,
3070
3085
  params: {
3071
- name: { type: 'string', description: 'Rule name (e.g., "PayNow Sales")' },
3072
- actionType: { type: 'string', description: 'Action type (e.g., "RECONCILE_WITH_DIRECT_CASH_ENTRY")' },
3086
+ name: { type: 'string', description: 'Rule name (e.g., "PayNow Sales", "STRIPE Payouts")' },
3087
+ actionType: { type: 'string', description: 'Action type: "RECONCILE_WITH_DIRECT_CASH_ENTRY" (creates cash entry on match)' },
3073
3088
  appliesToReconciliationAccountResourceId: { type: 'string', description: 'Bank account resourceId this rule applies to' },
3074
- configuration: { type: 'object', description: 'Rule configuration (allocation type, accounts, percentages, tax settings)' },
3089
+ configuration: { type: 'object', description: 'Required structure: { allocationType: "PERCENTAGE"|"FIXED", allocationDetails: [{ organizationAccountResourceId: "<account-id>", percentage: 100, taxProfileResourceId?: "<tax-id>" }] }' },
3075
3090
  },
3076
3091
  required: ['name', 'actionType', 'appliesToReconciliationAccountResourceId', 'configuration'],
3077
3092
  group: 'bank_rules',
@@ -3319,7 +3334,7 @@ Use for: software licenses, retainer services, recurring SaaS billing. Invoices
3319
3334
  description: 'Line items (name, unitPrice, quantity only — account/tax set at top level)',
3320
3335
  },
3321
3336
  },
3322
- required: ['interval', 'startDate', 'contactResourceId', 'lineItems', 'accountResourceId'],
3337
+ required: ['interval', 'startDate', 'contactResourceId', 'lineItems', 'accountResourceId', 'valueDate', 'dueDate'],
3323
3338
  group: 'subscriptions',
3324
3339
  readOnly: false,
3325
3340
  execute: async (ctx, input) => {
@@ -3483,11 +3498,11 @@ Use for: software licenses, retainer services, recurring SaaS billing. Invoices
3483
3498
  },
3484
3499
  {
3485
3500
  name: 'generate_fa_summary',
3486
- description: 'Generate fixed assets summary report grouped by type, contact, or currency.',
3501
+ description: 'Generate fixed assets summary report grouped by account, type, category, or status.',
3487
3502
  params: {
3488
3503
  primarySnapshotStartDate: { type: 'string', description: 'Period start date (YYYY-MM-DD)' },
3489
3504
  primarySnapshotEndDate: { type: 'string', description: 'Period end date (YYYY-MM-DD)' },
3490
- groupBy: { type: 'string', enum: ['CONTACT', 'CONTACT_GROUP', 'DUE_MONTH', 'RELATIONSHIP', 'CURRENCY'], description: 'Grouping dimension' },
3505
+ groupBy: { type: 'string', enum: ['ACCOUNT', 'TYPE', 'CATEGORY', 'STATUS'], description: 'Grouping dimension' },
3491
3506
  currencyCode: { type: 'string', description: 'Currency code' },
3492
3507
  },
3493
3508
  required: ['primarySnapshotStartDate', 'primarySnapshotEndDate', 'groupBy'],
@@ -3966,4 +3981,53 @@ Returns per-contact result: created, skipped (duplicate), or failed.`,
3966
3981
  };
3967
3982
  },
3968
3983
  },
3984
+ // ══════════════════════════════════════════════════════════════
3985
+ // ── Quick Fix (Bulk Update) ─────────────────────────────────
3986
+ // ══════════════════════════════════════════════════════════════
3987
+ {
3988
+ name: 'quick_fix_transactions',
3989
+ description: 'Bulk-update multiple transactions of the same type in one call. Pass resourceIds + attributes — only present fields are changed. ARAP: invoices, bills, customer-credit-notes, supplier-credit-notes. Accounting: journals, cash-entries. Schedulers: sale-schedules, purchase-schedules, subscription-schedules, journal-schedules. Common attributes: valueDate, contactResourceId, tags, capsuleResourceId. Entity-specific: dueDate (invoices/bills/CNs), invoiceNotes, templateResourceId, currencySettings, taxCurrencySettings, customFields. NOTE: valueDate (and dueDate for invoices/bills) must currently be included even if unchanged.',
3990
+ params: {
3991
+ entity: { type: 'string', enum: [...QUICK_FIX_ENTITIES], description: 'Transaction type to update' },
3992
+ resourceIds: { type: 'array', items: { type: 'string' }, description: 'Array of transaction resourceIds to update' },
3993
+ attributes: { type: 'object', description: 'Fields to update — only present fields are changed. Common: valueDate, contactResourceId, tags, capsuleResourceId. Invoices/bills: dueDate, currencySettings, taxCurrencySettings, customFields. Invoices/CNs: invoiceNotes, templateResourceId, billFrom, billTo. Schedulers: endDate, interval.' },
3994
+ },
3995
+ required: ['entity', 'resourceIds', 'attributes'],
3996
+ group: 'quick_fix',
3997
+ readOnly: false,
3998
+ execute: async (ctx, input) => quickFix(ctx.client, input.entity, {
3999
+ resourceIds: input.resourceIds,
4000
+ attributes: input.attributes,
4001
+ }),
4002
+ },
4003
+ {
4004
+ name: 'quick_fix_line_items',
4005
+ description: 'Bulk-update line items across multiple transactions. For ARAP (invoices, bills, credit notes) and accounting (journals, cash-entries): pass lineItemResourceIds + attributes. For schedulers: pass schedulerUpdates array with per-scheduler lineItemUpdates. ARAP line item attributes: name, quantity, unit, unitPrice, discount, itemResourceId, organizationAccountResourceId, taxProfileResourceId, classifierConfig. Bill/supplier-CN also: withholdingTax. Journal/cash-entry line items: organizationAccountResourceId, amount, description, taxProfileResourceId, classifierConfig.',
4006
+ params: {
4007
+ entity: { type: 'string', enum: [...QUICK_FIX_ENTITIES], description: 'Transaction type' },
4008
+ lineItemResourceIds: { type: 'array', items: { type: 'string' }, description: 'Line item resourceIds to update (ARAP + accounting entities)' },
4009
+ attributes: { type: 'object', description: 'Fields to update on all specified line items' },
4010
+ schedulerUpdates: { type: 'array', items: { type: 'object' }, description: 'Per-scheduler updates (scheduler entities only): [{ schedulerResourceId, lineItemUpdates: [{ arrayIndex, ...fields }] }]' },
4011
+ },
4012
+ required: ['entity'],
4013
+ group: 'quick_fix',
4014
+ readOnly: false,
4015
+ execute: async (ctx, input) => {
4016
+ const entity = input.entity;
4017
+ const isScheduler = ['sale-schedules', 'purchase-schedules', 'subscription-schedules', 'journal-schedules'].includes(entity);
4018
+ const body = {};
4019
+ if (isScheduler) {
4020
+ if (!input.schedulerUpdates)
4021
+ throw new Error('schedulerUpdates is required for scheduler entities (sale-schedules, purchase-schedules, subscription-schedules, journal-schedules)');
4022
+ body.schedulerUpdates = input.schedulerUpdates;
4023
+ }
4024
+ else {
4025
+ if (!input.lineItemResourceIds)
4026
+ throw new Error('lineItemResourceIds is required for non-scheduler entities');
4027
+ body.lineItemResourceIds = input.lineItemResourceIds;
4028
+ body.attributes = input.attributes ?? {};
4029
+ }
4030
+ return quickFixLineItems(ctx.client, entity, body);
4031
+ },
4032
+ },
3969
4033
  ];
package/dist/index.js CHANGED
@@ -49,6 +49,7 @@ import { registerContactGroupsCommand } from './commands/contact-groups.js';
49
49
  import { registerInventoryCommand } from './commands/inventory.js';
50
50
  import { registerSearchCommand } from './commands/search.js';
51
51
  import { registerCustomFieldsCommand } from './commands/custom-fields.js';
52
+ import { registerQuickFixCommand } from './commands/quick-fix.js';
52
53
  import { registerSchemaCommand } from './commands/schema.js';
53
54
  import { applyAllExamples } from './commands/help-examples.js';
54
55
  import { shouldShowPicker, showCommandPicker, attachSubcommandPickers } from './commands/picker.js';
@@ -161,6 +162,7 @@ registerContactGroupsCommand(program);
161
162
  registerInventoryCommand(program);
162
163
  registerSearchCommand(program);
163
164
  registerCustomFieldsCommand(program);
165
+ registerQuickFixCommand(program);
164
166
  registerSchemaCommand(program);
165
167
  applyAllExamples(program);
166
168
  // Add --org to every command that has --api-key (DRY: zero changes to command files)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaz-clio",
3
- "version": "4.30.10",
3
+ "version": "4.30.12",
4
4
  "description": "Clio — Command Line Interface Orchestrator for Jaz AI.",
5
5
  "type": "module",
6
6
  "bin": {