jaz-clio 4.25.1 → 4.25.3
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 +1 -1
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/jobs/SKILL.md +1 -1
- package/assets/skills/transaction-recipes/SKILL.md +1 -1
- package/dist/commands/bank-rules.js +8 -1
- package/dist/commands/bills.js +23 -0
- package/dist/commands/contacts.js +5 -1
- package/dist/commands/currencies.js +15 -12
- package/dist/commands/currency-rates.js +21 -18
- package/dist/commands/fixed-assets.js +14 -2
- package/dist/commands/invoices.js +23 -0
- package/dist/commands/journals.js +6 -0
- package/dist/commands/schedulers.js +15 -37
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-api
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.3
|
|
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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-conversion
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.3
|
|
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.25.
|
|
3
|
+
version: 4.25.3
|
|
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.25.
|
|
3
|
+
version: 4.25.3
|
|
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.
|
|
@@ -45,13 +45,20 @@ export function registerBankRulesCommand(program) {
|
|
|
45
45
|
cmd
|
|
46
46
|
.command('search <query>')
|
|
47
47
|
.description('Search bank rules')
|
|
48
|
+
.option('--account <resourceId>', 'Filter by bank account resourceId')
|
|
49
|
+
.option('--sort <field>', 'Sort field (default: name)')
|
|
50
|
+
.option('--order <direction>', 'Sort order: ASC or DESC (default: ASC)')
|
|
48
51
|
.option('--limit <n>', 'Max results', parsePositiveInt)
|
|
49
52
|
.option('--offset <n>', 'Offset', parseNonNegativeInt)
|
|
50
53
|
.option('--api-key <key>', 'API key')
|
|
51
54
|
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
52
55
|
.option('--json', 'JSON output')
|
|
53
56
|
.action((query, opts) => apiAction(async (client) => {
|
|
54
|
-
const
|
|
57
|
+
const filter = { name: { contains: query } };
|
|
58
|
+
if (opts.account)
|
|
59
|
+
filter.bankAccountResourceId = { eq: opts.account };
|
|
60
|
+
const sort = { sortBy: [opts.sort ?? 'name'], order: (opts.order ?? 'ASC') };
|
|
61
|
+
const result = await paginatedFetch(opts, ({ limit, offset }) => searchBankRules(client, { filter, limit, offset, sort }), { label: 'Searching bank rules', defaultLimit: 20 });
|
|
55
62
|
outputList(result, BANK_RULES_COLUMNS, opts, 'Bank Rules'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
56
63
|
})(opts));
|
|
57
64
|
cmd
|
package/dist/commands/bills.js
CHANGED
|
@@ -75,8 +75,13 @@ export function registerBillsCommand(program) {
|
|
|
75
75
|
.option('--ref <reference>', 'Filter by reference (contains)')
|
|
76
76
|
.option('--status <status>', 'Filter by status (DRAFT, UNPAID, PAID, OVERDUE, VOIDED)')
|
|
77
77
|
.option('--contact <resourceId>', 'Filter by contact name or resourceId')
|
|
78
|
+
.option('--tag <name>', 'Filter by tag')
|
|
79
|
+
.option('--min-amount <n>', 'Minimum total amount', parseMoney)
|
|
80
|
+
.option('--max-amount <n>', 'Maximum total amount', parseMoney)
|
|
78
81
|
.option('--from <YYYY-MM-DD>', 'Filter from date (inclusive)')
|
|
79
82
|
.option('--to <YYYY-MM-DD>', 'Filter to date (inclusive)')
|
|
83
|
+
.option('--due-from <YYYY-MM-DD>', 'Filter by due date from (inclusive)')
|
|
84
|
+
.option('--due-to <YYYY-MM-DD>', 'Filter by due date to (inclusive)')
|
|
80
85
|
.option('--sort <field>', 'Sort field (default: valueDate)')
|
|
81
86
|
.option('--order <direction>', 'Sort order: ASC or DESC (default: DESC)')
|
|
82
87
|
.option('--limit <n>', 'Max results (default 20)', parsePositiveInt)
|
|
@@ -99,6 +104,16 @@ export function registerBillsCommand(program) {
|
|
|
99
104
|
filter.status = { eq: opts.status };
|
|
100
105
|
if (opts.contact)
|
|
101
106
|
filter.contactResourceId = { eq: opts.contact };
|
|
107
|
+
if (opts.tag)
|
|
108
|
+
filter.tags = { eq: opts.tag };
|
|
109
|
+
if (opts.minAmount !== undefined || opts.maxAmount !== undefined) {
|
|
110
|
+
const af = {};
|
|
111
|
+
if (opts.minAmount !== undefined)
|
|
112
|
+
af.gte = opts.minAmount;
|
|
113
|
+
if (opts.maxAmount !== undefined)
|
|
114
|
+
af.lte = opts.maxAmount;
|
|
115
|
+
filter.totalAmount = af;
|
|
116
|
+
}
|
|
102
117
|
if (opts.from || opts.to) {
|
|
103
118
|
const dateFilter = {};
|
|
104
119
|
if (opts.from)
|
|
@@ -107,6 +122,14 @@ export function registerBillsCommand(program) {
|
|
|
107
122
|
dateFilter.lte = opts.to;
|
|
108
123
|
filter.valueDate = dateFilter;
|
|
109
124
|
}
|
|
125
|
+
if (opts.dueFrom || opts.dueTo) {
|
|
126
|
+
const df = {};
|
|
127
|
+
if (opts.dueFrom)
|
|
128
|
+
df.gte = opts.dueFrom;
|
|
129
|
+
if (opts.dueTo)
|
|
130
|
+
df.lte = opts.dueTo;
|
|
131
|
+
filter.dueDate = df;
|
|
132
|
+
}
|
|
110
133
|
const searchFilter = Object.keys(filter).length > 0 ? filter : undefined;
|
|
111
134
|
const sort = { sortBy: [opts.sort ?? 'valueDate'], order: (opts.order ?? 'DESC') };
|
|
112
135
|
const result = await paginatedFetch(opts, ({ limit, offset }) => searchBills(client, { filter: searchFilter, limit, offset, sort }), { label: 'Searching bills', defaultLimit: 20 });
|
|
@@ -40,6 +40,8 @@ export function registerContactsCommand(program) {
|
|
|
40
40
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
41
41
|
.option('--customer', 'Filter to customers only')
|
|
42
42
|
.option('--supplier', 'Filter to suppliers only')
|
|
43
|
+
.option('--status <status>', 'Filter by status (ACTIVE, INACTIVE; default: ACTIVE)')
|
|
44
|
+
.option('--email <email>', 'Filter by email (contains)')
|
|
43
45
|
.option('--sort <field>', 'Sort field (default: name)')
|
|
44
46
|
.option('--order <direction>', 'Sort order: ASC or DESC (default: ASC)')
|
|
45
47
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
@@ -47,13 +49,15 @@ export function registerContactsCommand(program) {
|
|
|
47
49
|
.option('--json', 'Output as JSON')
|
|
48
50
|
.action((query, opts) => apiAction(async (client) => {
|
|
49
51
|
const filter = {
|
|
50
|
-
status: { eq: 'ACTIVE' },
|
|
52
|
+
status: { eq: opts.status ?? 'ACTIVE' },
|
|
51
53
|
name: { contains: query },
|
|
52
54
|
};
|
|
53
55
|
if (opts.customer)
|
|
54
56
|
filter.customer = { eq: true };
|
|
55
57
|
if (opts.supplier)
|
|
56
58
|
filter.supplier = { eq: true };
|
|
59
|
+
if (opts.email)
|
|
60
|
+
filter.email = { contains: opts.email };
|
|
57
61
|
const sort = { sortBy: [opts.sort ?? 'name'], order: (opts.order ?? 'ASC') };
|
|
58
62
|
const result = await paginatedFetch(opts, ({ limit, offset }) => searchContacts(client, { filter, limit, offset, sort }), { label: 'Searching contacts', defaultLimit: 20 });
|
|
59
63
|
outputList(result, CONTACTS_COLUMNS, opts, 'Contacts'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { listCurrencies, addCurrency } from '../core/api/currencies.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
|
+
import { outputList } from './output.js';
|
|
5
|
+
const CURRENCIES_COLUMNS = [
|
|
6
|
+
{ key: 'currencyCode', header: 'Code' },
|
|
7
|
+
{ key: 'currencyName', header: 'Name' },
|
|
8
|
+
{ key: 'currencySymbol', header: 'Symbol' },
|
|
9
|
+
{ key: 'baseCurrency', header: 'Base' },
|
|
10
|
+
];
|
|
4
11
|
export function registerCurrenciesCommand(program) {
|
|
5
12
|
const cmd = program
|
|
6
13
|
.command('currencies')
|
|
@@ -10,31 +17,27 @@ export function registerCurrenciesCommand(program) {
|
|
|
10
17
|
.command('list')
|
|
11
18
|
.description('List enabled currencies for the organization')
|
|
12
19
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
20
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
13
21
|
.option('--json', 'Output as JSON')
|
|
14
22
|
.action(apiAction(async (client, opts) => {
|
|
15
23
|
const res = await listCurrencies(client);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
console.log(chalk.bold(`Currencies (${res.data.length}):\n`));
|
|
21
|
-
for (const c of res.data) {
|
|
22
|
-
const base = c.baseCurrency ? chalk.dim(' (base)') : '';
|
|
23
|
-
console.log(` ${chalk.cyan(c.currencyCode)} ${c.currencyName} ${chalk.dim(c.currencySymbol)}${base}`);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
24
|
+
const result = { data: res.data, totalElements: res.data.length, totalPages: 1, truncated: false };
|
|
25
|
+
outputList(result, CURRENCIES_COLUMNS, opts, 'Currencies'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
26
26
|
}));
|
|
27
27
|
// ── clio currencies add ───────────────────────────────────────
|
|
28
28
|
cmd
|
|
29
29
|
.command('add <codes...>')
|
|
30
30
|
.description('Add currencies to the organization (e.g. clio currencies add EUR GBP)')
|
|
31
31
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
32
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
32
33
|
.option('--json', 'Output as JSON')
|
|
33
34
|
.action((codes, opts) => apiAction(async (client) => {
|
|
34
35
|
const upperCodes = codes.map(c => c.toUpperCase());
|
|
35
36
|
const res = await addCurrency(client, upperCodes);
|
|
36
|
-
if (opts.json) {
|
|
37
|
-
|
|
37
|
+
if (opts.json || opts.format) {
|
|
38
|
+
const data = Array.isArray(res.data) ? res.data : [res.data];
|
|
39
|
+
const result = { data, totalElements: data.length, totalPages: 1, truncated: false };
|
|
40
|
+
outputList(result, CURRENCIES_COLUMNS, opts, 'Currencies'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
38
41
|
}
|
|
39
42
|
else {
|
|
40
43
|
console.log(chalk.green(`Added currencies: ${upperCodes.join(', ')}`));
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { listCurrencyRates, addCurrencyRate, updateCurrencyRate, startCurrencyRatesImportJob, getCurrencyRatesImportJobStatus, } from '../core/api/currencies.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
|
+
import { outputList } from './output.js';
|
|
5
|
+
import { formatId } from './format-helpers.js';
|
|
4
6
|
import { parsePositiveInt, parseNonNegativeInt, requireFields } from './parsers.js';
|
|
5
|
-
import { paginatedFetch
|
|
7
|
+
import { paginatedFetch } from './pagination.js';
|
|
8
|
+
const RATES_COLUMNS = [
|
|
9
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
|
+
{ key: 'rate', header: 'Rate' },
|
|
11
|
+
{ key: 'rateApplicableFrom', header: 'From' },
|
|
12
|
+
{ key: 'rateApplicableTo', header: 'To' },
|
|
13
|
+
];
|
|
6
14
|
export function registerCurrencyRatesCommand(program) {
|
|
7
15
|
const cmd = program
|
|
8
16
|
.command('currency-rates')
|
|
@@ -16,23 +24,12 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
16
24
|
.option('--all', 'Fetch all pages')
|
|
17
25
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
18
26
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
27
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
19
28
|
.option('--json', 'Output as JSON')
|
|
20
29
|
.action((currencyCode, opts) => apiAction(async (client) => {
|
|
21
30
|
const code = currencyCode.toUpperCase();
|
|
22
31
|
const result = await paginatedFetch(opts, (p) => listCurrencyRates(client, code, p), { label: `Fetching ${code} rates` });
|
|
23
|
-
|
|
24
|
-
console.log(paginatedJson(result, opts));
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
console.log(chalk.bold(`${code} Rates (${result.data.length} of ${result.totalElements}):\n`));
|
|
28
|
-
const { items, overflow } = displaySlice(result.data);
|
|
29
|
-
for (const r of items) {
|
|
30
|
-
const to = r.rateApplicableTo || '(open)';
|
|
31
|
-
console.log(` ${chalk.cyan(r.resourceId)} ${chalk.bold(String(r.rate))} ${r.rateApplicableFrom} — ${to}`);
|
|
32
|
-
}
|
|
33
|
-
if (overflow > 0)
|
|
34
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
35
|
-
}
|
|
32
|
+
outputList(result, RATES_COLUMNS, opts, `${code} Rates`); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
36
33
|
})(opts));
|
|
37
34
|
// ── clio currency-rates add ───────────────────────────────────
|
|
38
35
|
cmd
|
|
@@ -42,6 +39,7 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
42
39
|
.option('--from <YYYY-MM-DD>', 'Rate applicable from date')
|
|
43
40
|
.option('--to <YYYY-MM-DD>', 'Rate applicable to date (optional)')
|
|
44
41
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
42
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
45
43
|
.option('--json', 'Output as JSON')
|
|
46
44
|
.action((currencyCode, opts) => apiAction(async (client) => {
|
|
47
45
|
requireFields(opts, [
|
|
@@ -56,8 +54,9 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
56
54
|
if (opts.to)
|
|
57
55
|
data.rateApplicableTo = opts.to;
|
|
58
56
|
const res = await addCurrencyRate(client, code, data);
|
|
59
|
-
if (opts.json) {
|
|
60
|
-
|
|
57
|
+
if (opts.json || opts.format) {
|
|
58
|
+
const result = { data: [res.data], totalElements: 1, totalPages: 1, truncated: false };
|
|
59
|
+
outputList(result, RATES_COLUMNS, opts, `${code} Rates`); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
61
60
|
}
|
|
62
61
|
else {
|
|
63
62
|
console.log(chalk.green(`Rate added for ${code}: ${opts.rate} (from ${opts.from})`));
|
|
@@ -71,6 +70,7 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
71
70
|
.option('--from <YYYY-MM-DD>', 'Rate applicable from date')
|
|
72
71
|
.option('--to <YYYY-MM-DD>', 'Rate applicable to date (optional)')
|
|
73
72
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
73
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
74
74
|
.option('--json', 'Output as JSON')
|
|
75
75
|
.action((currencyCode, rateResourceId, opts) => apiAction(async (client) => {
|
|
76
76
|
requireFields(opts, [
|
|
@@ -85,8 +85,9 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
85
85
|
if (opts.to)
|
|
86
86
|
data.rateApplicableTo = opts.to;
|
|
87
87
|
const res = await updateCurrencyRate(client, code, rateResourceId, data);
|
|
88
|
-
if (opts.json) {
|
|
89
|
-
|
|
88
|
+
if (opts.json || opts.format) {
|
|
89
|
+
const result = { data: [res.data], totalElements: 1, totalPages: 1, truncated: false };
|
|
90
|
+
outputList(result, RATES_COLUMNS, opts, `${code} Rates`); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
90
91
|
}
|
|
91
92
|
else {
|
|
92
93
|
console.log(chalk.green(`Rate updated for ${code}: ${opts.rate}`));
|
|
@@ -98,6 +99,7 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
98
99
|
.description('Import currency rates from a CSV file URL')
|
|
99
100
|
.option('--csv-url <url>', 'URL of the CSV file to import (required)')
|
|
100
101
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
102
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
101
103
|
.option('--json', 'Output as JSON')
|
|
102
104
|
.action((currencyCode, opts) => apiAction(async (client) => {
|
|
103
105
|
requireFields(opts, [
|
|
@@ -121,6 +123,7 @@ export function registerCurrencyRatesCommand(program) {
|
|
|
121
123
|
.command('import-status <jobId>')
|
|
122
124
|
.description('Check the status of a currency rates import job')
|
|
123
125
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
126
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
124
127
|
.option('--json', 'Output as JSON')
|
|
125
128
|
.action((jobId, opts) => apiAction(async (client) => {
|
|
126
129
|
const res = await getCurrencyRatesImportJobStatus(client, jobId);
|
|
@@ -53,8 +53,13 @@ export function registerFixedAssetsCommand(program) {
|
|
|
53
53
|
cmd
|
|
54
54
|
.command('search')
|
|
55
55
|
.description('Search fixed assets')
|
|
56
|
-
.option('--query <term>', 'Search by name
|
|
56
|
+
.option('--query <term>', 'Search by name')
|
|
57
57
|
.option('--status <status>', 'Filter by status (ONGOING, COMPLETED, DISPOSED, DRAFT)')
|
|
58
|
+
.option('--tag <name>', 'Filter by tag')
|
|
59
|
+
.option('--category <cat>', 'Filter by category')
|
|
60
|
+
.option('--reference <ref>', 'Filter by reference (contains)')
|
|
61
|
+
.option('--sort <field>', 'Sort field (default: name)')
|
|
62
|
+
.option('--order <direction>', 'Sort order: ASC or DESC (default: ASC)')
|
|
58
63
|
.option('--limit <n>', 'Max results', parsePositiveInt)
|
|
59
64
|
.option('--offset <n>', 'Offset', parseNonNegativeInt)
|
|
60
65
|
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
@@ -66,7 +71,14 @@ export function registerFixedAssetsCommand(program) {
|
|
|
66
71
|
filter.name = { contains: opts.query };
|
|
67
72
|
if (opts.status)
|
|
68
73
|
filter.status = { eq: opts.status };
|
|
69
|
-
|
|
74
|
+
if (opts.tag)
|
|
75
|
+
filter.tags = { eq: opts.tag };
|
|
76
|
+
if (opts.category)
|
|
77
|
+
filter.category = { eq: opts.category };
|
|
78
|
+
if (opts.reference)
|
|
79
|
+
filter.reference = { contains: opts.reference };
|
|
80
|
+
const sort = { sortBy: [opts.sort ?? 'name'], order: (opts.order ?? 'ASC') };
|
|
81
|
+
const result = await paginatedFetch(opts, ({ limit, offset }) => searchFixedAssets(client, { filter, limit, offset, sort }), { label: 'Searching fixed assets', defaultLimit: 20 });
|
|
70
82
|
outputList(result, FA_COLUMNS, opts, 'Fixed Assets'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
71
83
|
}));
|
|
72
84
|
cmd
|
|
@@ -77,8 +77,13 @@ export function registerInvoicesCommand(program) {
|
|
|
77
77
|
.option('--ref <reference>', 'Filter by reference (contains)')
|
|
78
78
|
.option('--status <status>', 'Filter by status (DRAFT, UNPAID, PAID, OVERDUE, VOIDED)')
|
|
79
79
|
.option('--contact <resourceId>', 'Filter by contact name or resourceId')
|
|
80
|
+
.option('--tag <name>', 'Filter by tag')
|
|
81
|
+
.option('--min-amount <n>', 'Minimum total amount', parseMoney)
|
|
82
|
+
.option('--max-amount <n>', 'Maximum total amount', parseMoney)
|
|
80
83
|
.option('--from <YYYY-MM-DD>', 'Filter from date (inclusive)')
|
|
81
84
|
.option('--to <YYYY-MM-DD>', 'Filter to date (inclusive)')
|
|
85
|
+
.option('--due-from <YYYY-MM-DD>', 'Filter by due date from (inclusive)')
|
|
86
|
+
.option('--due-to <YYYY-MM-DD>', 'Filter by due date to (inclusive)')
|
|
82
87
|
.option('--sort <field>', 'Sort field (default: valueDate)')
|
|
83
88
|
.option('--order <direction>', 'Sort order: ASC or DESC (default: DESC)')
|
|
84
89
|
.option('--limit <n>', 'Max results (default 20)', parsePositiveInt)
|
|
@@ -101,6 +106,16 @@ export function registerInvoicesCommand(program) {
|
|
|
101
106
|
filter.status = { eq: opts.status };
|
|
102
107
|
if (opts.contact)
|
|
103
108
|
filter.contactResourceId = { eq: opts.contact };
|
|
109
|
+
if (opts.tag)
|
|
110
|
+
filter.tags = { eq: opts.tag };
|
|
111
|
+
if (opts.minAmount !== undefined || opts.maxAmount !== undefined) {
|
|
112
|
+
const af = {};
|
|
113
|
+
if (opts.minAmount !== undefined)
|
|
114
|
+
af.gte = opts.minAmount;
|
|
115
|
+
if (opts.maxAmount !== undefined)
|
|
116
|
+
af.lte = opts.maxAmount;
|
|
117
|
+
filter.totalAmount = af;
|
|
118
|
+
}
|
|
104
119
|
if (opts.from || opts.to) {
|
|
105
120
|
const dateFilter = {};
|
|
106
121
|
if (opts.from)
|
|
@@ -109,6 +124,14 @@ export function registerInvoicesCommand(program) {
|
|
|
109
124
|
dateFilter.lte = opts.to;
|
|
110
125
|
filter.valueDate = dateFilter;
|
|
111
126
|
}
|
|
127
|
+
if (opts.dueFrom || opts.dueTo) {
|
|
128
|
+
const df = {};
|
|
129
|
+
if (opts.dueFrom)
|
|
130
|
+
df.gte = opts.dueFrom;
|
|
131
|
+
if (opts.dueTo)
|
|
132
|
+
df.lte = opts.dueTo;
|
|
133
|
+
filter.dueDate = df;
|
|
134
|
+
}
|
|
112
135
|
const searchFilter = Object.keys(filter).length > 0 ? filter : undefined;
|
|
113
136
|
const sort = { sortBy: [opts.sort ?? 'valueDate'], order: (opts.order ?? 'DESC') };
|
|
114
137
|
const result = await paginatedFetch(opts, ({ limit, offset }) => searchInvoices(client, { filter: searchFilter, limit, offset, sort }), { label: 'Searching invoices', defaultLimit: 20 });
|
|
@@ -42,6 +42,8 @@ export function registerJournalsCommand(program) {
|
|
|
42
42
|
.option('--from <YYYY-MM-DD>', 'Filter from date (inclusive)')
|
|
43
43
|
.option('--to <YYYY-MM-DD>', 'Filter to date (inclusive)')
|
|
44
44
|
.option('--status <status>', 'Filter by status (DRAFT, FINALIZED)')
|
|
45
|
+
.option('--tag <name>', 'Filter by tag')
|
|
46
|
+
.option('--type <type>', 'Filter by type (JOURNAL_MANUAL, JOURNAL_DIRECT_CASH_IN, JOURNAL_DIRECT_CASH_OUT)')
|
|
45
47
|
.option('--sort <field>', 'Sort field (default: valueDate)')
|
|
46
48
|
.option('--order <direction>', 'Sort order: ASC or DESC (default: DESC)')
|
|
47
49
|
.option('--limit <n>', 'Max results (default 20)', parsePositiveInt)
|
|
@@ -57,6 +59,10 @@ export function registerJournalsCommand(program) {
|
|
|
57
59
|
filter.reference = { contains: opts.ref };
|
|
58
60
|
if (opts.status)
|
|
59
61
|
filter.status = { eq: opts.status };
|
|
62
|
+
if (opts.tag)
|
|
63
|
+
filter.tags = { eq: opts.tag };
|
|
64
|
+
if (opts.type)
|
|
65
|
+
filter.type = { eq: opts.type };
|
|
60
66
|
if (opts.from || opts.to) {
|
|
61
67
|
const dateFilter = {};
|
|
62
68
|
if (opts.from)
|
|
@@ -4,8 +4,16 @@ import { createScheduledInvoice } from '../core/api/invoices.js';
|
|
|
4
4
|
import { createScheduledBill } from '../core/api/bills.js';
|
|
5
5
|
import { createScheduledJournal } from '../core/api/journals.js';
|
|
6
6
|
import { apiAction } from './api-action.js';
|
|
7
|
+
import { outputList } from './output.js';
|
|
8
|
+
import { formatId } from './format-helpers.js';
|
|
7
9
|
import { parsePositiveInt, parseNonNegativeInt, readBodyInput, requireFields, parseLineItems, parseJournalEntries } from './parsers.js';
|
|
8
|
-
import { paginatedFetch
|
|
10
|
+
import { paginatedFetch } from './pagination.js';
|
|
11
|
+
const SCHEDULER_COLUMNS = [
|
|
12
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
13
|
+
{ key: 'repeat', header: 'Repeat' },
|
|
14
|
+
{ key: 'startDate', header: 'Start' },
|
|
15
|
+
{ key: 'status', header: 'Status' },
|
|
16
|
+
];
|
|
9
17
|
export function registerSchedulersCommand(program) {
|
|
10
18
|
const cmd = program
|
|
11
19
|
.command('schedulers')
|
|
@@ -19,21 +27,11 @@ export function registerSchedulersCommand(program) {
|
|
|
19
27
|
.option('--all', 'Fetch all pages')
|
|
20
28
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
21
29
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
30
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
22
31
|
.option('--json', 'Output as JSON')
|
|
23
32
|
.action(apiAction(async (client, opts) => {
|
|
24
33
|
const result = await paginatedFetch(opts, (p) => listScheduledInvoices(client, p), { label: 'Fetching scheduled invoices' });
|
|
25
|
-
|
|
26
|
-
console.log(paginatedJson(result, opts));
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
console.log(chalk.bold(`Scheduled Invoices (${result.data.length} of ${result.totalElements}):\n`));
|
|
30
|
-
const { items, overflow } = displaySlice(result.data);
|
|
31
|
-
for (const s of items) {
|
|
32
|
-
console.log(` ${chalk.cyan(s.resourceId)} ${s.repeat} ${s.startDate} ${chalk.dim(s.status)}`);
|
|
33
|
-
}
|
|
34
|
-
if (overflow > 0)
|
|
35
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
36
|
-
}
|
|
34
|
+
outputList(result, SCHEDULER_COLUMNS, opts, 'Scheduled Invoices'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
37
35
|
}));
|
|
38
36
|
// ── clio schedulers list-bills ────────────────────────────────
|
|
39
37
|
cmd
|
|
@@ -44,21 +42,11 @@ export function registerSchedulersCommand(program) {
|
|
|
44
42
|
.option('--all', 'Fetch all pages')
|
|
45
43
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
46
44
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
45
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
47
46
|
.option('--json', 'Output as JSON')
|
|
48
47
|
.action(apiAction(async (client, opts) => {
|
|
49
48
|
const result = await paginatedFetch(opts, (p) => listScheduledBills(client, p), { label: 'Fetching scheduled bills' });
|
|
50
|
-
|
|
51
|
-
console.log(paginatedJson(result, opts));
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
console.log(chalk.bold(`Scheduled Bills (${result.data.length} of ${result.totalElements}):\n`));
|
|
55
|
-
const { items, overflow } = displaySlice(result.data);
|
|
56
|
-
for (const s of items) {
|
|
57
|
-
console.log(` ${chalk.cyan(s.resourceId)} ${s.repeat} ${s.startDate} ${chalk.dim(s.status)}`);
|
|
58
|
-
}
|
|
59
|
-
if (overflow > 0)
|
|
60
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
61
|
-
}
|
|
49
|
+
outputList(result, SCHEDULER_COLUMNS, opts, 'Scheduled Bills'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
62
50
|
}));
|
|
63
51
|
// ── clio schedulers list-journals ─────────────────────────────
|
|
64
52
|
cmd
|
|
@@ -69,21 +57,11 @@ export function registerSchedulersCommand(program) {
|
|
|
69
57
|
.option('--all', 'Fetch all pages')
|
|
70
58
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
71
59
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
60
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
72
61
|
.option('--json', 'Output as JSON')
|
|
73
62
|
.action(apiAction(async (client, opts) => {
|
|
74
63
|
const result = await paginatedFetch(opts, (p) => listScheduledJournals(client, p), { label: 'Fetching scheduled journals' });
|
|
75
|
-
|
|
76
|
-
console.log(paginatedJson(result, opts));
|
|
77
|
-
}
|
|
78
|
-
else {
|
|
79
|
-
console.log(chalk.bold(`Scheduled Journals (${result.data.length} of ${result.totalElements}):\n`));
|
|
80
|
-
const { items, overflow } = displaySlice(result.data);
|
|
81
|
-
for (const s of items) {
|
|
82
|
-
console.log(` ${chalk.cyan(s.resourceId)} ${s.repeat} ${s.startDate} ${chalk.dim(s.status)}`);
|
|
83
|
-
}
|
|
84
|
-
if (overflow > 0)
|
|
85
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
86
|
-
}
|
|
64
|
+
outputList(result, SCHEDULER_COLUMNS, opts, 'Scheduled Journals'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
87
65
|
}));
|
|
88
66
|
// ── clio schedulers create-invoice ────────────────────────────
|
|
89
67
|
cmd
|