jaz-clio 4.35.0 → 4.35.1
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/cli/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/accounts.js +6 -6
- package/dist/commands/attachments.js +8 -8
- package/dist/commands/auth.js +41 -41
- package/dist/commands/bank-rules.js +14 -14
- package/dist/commands/bank.js +27 -27
- package/dist/commands/bills.js +35 -35
- package/dist/commands/bookmarks.js +8 -8
- package/dist/commands/calc.js +2 -2
- package/dist/commands/capsules.js +14 -14
- package/dist/commands/cash-entry.js +16 -16
- package/dist/commands/cash-transfer.js +4 -4
- package/dist/commands/cashflow.js +2 -2
- package/dist/commands/contact-groups.js +10 -10
- package/dist/commands/contacts.js +14 -14
- package/dist/commands/currencies.js +2 -2
- package/dist/commands/currency-rates.js +8 -8
- package/dist/commands/custom-fields.js +12 -12
- package/dist/commands/customer-credit-notes.js +30 -30
- package/dist/commands/draft-helpers.js +12 -12
- package/dist/commands/exports.js +4 -4
- package/dist/commands/fixed-assets.js +23 -23
- package/dist/commands/format-helpers.js +5 -0
- package/dist/commands/help-examples.js +2 -2
- package/dist/commands/init.js +8 -8
- package/dist/commands/inventory.js +7 -7
- package/dist/commands/invoices.js +36 -36
- package/dist/commands/items.js +11 -11
- package/dist/commands/jobs.js +33 -33
- package/dist/commands/journals.js +27 -27
- package/dist/commands/kb.js +6 -6
- package/dist/commands/magic.js +40 -40
- package/dist/commands/nano-classifiers.js +8 -8
- package/dist/commands/org-users.js +5 -5
- package/dist/commands/org.js +8 -8
- package/dist/commands/output.js +3 -3
- package/dist/commands/pagination.js +2 -2
- package/dist/commands/parsers.js +20 -20
- package/dist/commands/payments.js +9 -9
- package/dist/commands/picker.js +5 -5
- package/dist/commands/quick-fix.js +8 -8
- package/dist/commands/recipe.js +16 -16
- package/dist/commands/reports.js +11 -11
- package/dist/commands/resolve.js +8 -8
- package/dist/commands/schedulers.js +25 -25
- package/dist/commands/schema.js +15 -24
- package/dist/commands/search.js +4 -4
- package/dist/commands/subscriptions.js +17 -17
- package/dist/commands/supplier-credit-notes.js +28 -28
- package/dist/commands/tags.js +10 -10
- package/dist/commands/tax-profiles.js +11 -11
- package/dist/commands/ui/table.js +2 -3
- package/dist/commands/ui/theme.js +1 -0
- package/dist/commands/update.js +2 -2
- package/dist/commands/versions.js +3 -3
- package/dist/core/calc/format.js +126 -126
- package/dist/core/jobs/document-collection/tools/ingest/format.js +25 -25
- package/dist/core/jobs/format.js +23 -23
- package/dist/core/jobs/payment-run/tools/bank-file/format.js +7 -7
- package/dist/core/jobs/payment-run/tools/outstanding/format.js +9 -9
- package/dist/core/jobs/statutory-filing/tools/sg-tax/format-sg.js +19 -19
- package/dist/index.js +11 -11
- package/package.json +1 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { listAccounts, searchAccounts, createAccount, deleteAccount } from '../core/api/chart-of-accounts.js';
|
|
3
2
|
import { findExistingAccount, normalizeAccountType } from '../core/api/guards.js';
|
|
4
3
|
import { apiAction } from './api-action.js';
|
|
@@ -6,6 +5,7 @@ import { outputList } from './output.js';
|
|
|
6
5
|
import { parsePositiveInt, parseNonNegativeInt, readBodyInput, requireFields } from './parsers.js';
|
|
7
6
|
import { paginatedFetch } from './pagination.js';
|
|
8
7
|
import { formatId } from './format-helpers.js';
|
|
8
|
+
import { accent, highlight, success } from './ui/theme.js';
|
|
9
9
|
const ACCOUNTS_COLUMNS = [
|
|
10
10
|
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
11
11
|
{ key: 'code', header: 'Code' },
|
|
@@ -74,8 +74,8 @@ export function registerAccountsCommand(program) {
|
|
|
74
74
|
console.log(JSON.stringify(existing, null, 2));
|
|
75
75
|
}
|
|
76
76
|
else {
|
|
77
|
-
console.log(
|
|
78
|
-
console.log(
|
|
77
|
+
console.log(accent(`Account "${acctName}" already exists`));
|
|
78
|
+
console.log(highlight('ID:'), existing.resourceId);
|
|
79
79
|
}
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
@@ -105,8 +105,8 @@ export function registerAccountsCommand(program) {
|
|
|
105
105
|
console.log(JSON.stringify(res.data, null, 2));
|
|
106
106
|
}
|
|
107
107
|
else {
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(
|
|
108
|
+
console.log(success(`Account created: ${res.data.name} (${res.data.code})`));
|
|
109
|
+
console.log(highlight('ID:'), res.data.resourceId);
|
|
110
110
|
}
|
|
111
111
|
}));
|
|
112
112
|
// ── clio accounts delete ──────────────────────────────────────
|
|
@@ -122,7 +122,7 @@ export function registerAccountsCommand(program) {
|
|
|
122
122
|
console.log(JSON.stringify({ deleted: true, resourceId }));
|
|
123
123
|
}
|
|
124
124
|
else {
|
|
125
|
-
console.log(
|
|
125
|
+
console.log(success(`Account ${resourceId} deleted.`));
|
|
126
126
|
}
|
|
127
127
|
})(opts));
|
|
128
128
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { readFileSync } from 'node:fs';
|
|
3
2
|
import { basename, extname, resolve } from 'node:path';
|
|
4
3
|
import { listAttachments, addAttachment, deleteAttachment, fetchAttachmentTable } from '../core/api/attachments.js';
|
|
5
4
|
import { apiAction } from './api-action.js';
|
|
6
5
|
import { outputList } from './output.js';
|
|
7
6
|
import { formatId } from './format-helpers.js';
|
|
7
|
+
import { danger, success } from './ui/theme.js';
|
|
8
8
|
const ATTACHMENTS_COLUMNS = [
|
|
9
9
|
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
10
|
{ key: 'fileName', header: 'File Name' },
|
|
@@ -38,7 +38,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
38
38
|
.action(apiAction(async (client, opts) => {
|
|
39
39
|
const btType = opts.type;
|
|
40
40
|
if (!BT_TYPES.includes(btType)) {
|
|
41
|
-
console.error(
|
|
41
|
+
console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
|
|
42
42
|
process.exit(1);
|
|
43
43
|
}
|
|
44
44
|
const result = await listAttachments(client, btType, opts.id);
|
|
@@ -65,11 +65,11 @@ export function registerAttachmentsCommand(program) {
|
|
|
65
65
|
.action(apiAction(async (client, opts) => {
|
|
66
66
|
const btType = opts.type;
|
|
67
67
|
if (!BT_TYPES.includes(btType)) {
|
|
68
|
-
console.error(
|
|
68
|
+
console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
if (!opts.attachmentId && !opts.url && !opts.file) {
|
|
72
|
-
console.error(
|
|
72
|
+
console.error(danger('Provide --file, --url, or --attachment-id'));
|
|
73
73
|
process.exit(1);
|
|
74
74
|
}
|
|
75
75
|
let file;
|
|
@@ -87,7 +87,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
87
87
|
// Download from URL, then upload as file
|
|
88
88
|
const res = await fetch(opts.url);
|
|
89
89
|
if (!res.ok) {
|
|
90
|
-
console.error(
|
|
90
|
+
console.error(danger(`Failed to download: ${res.status} ${res.statusText}`));
|
|
91
91
|
process.exit(1);
|
|
92
92
|
}
|
|
93
93
|
const buffer = await res.arrayBuffer();
|
|
@@ -108,7 +108,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
108
108
|
console.log(JSON.stringify(result, null, 2));
|
|
109
109
|
}
|
|
110
110
|
else {
|
|
111
|
-
console.log(
|
|
111
|
+
console.log(success('Attachment added.'));
|
|
112
112
|
}
|
|
113
113
|
}));
|
|
114
114
|
// ── clio attachments delete ────────────────────────────────────
|
|
@@ -123,7 +123,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
123
123
|
.action((attachmentResourceId, rawOpts) => {
|
|
124
124
|
const btType = rawOpts.type;
|
|
125
125
|
if (!BT_TYPES.includes(btType)) {
|
|
126
|
-
console.error(
|
|
126
|
+
console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
|
|
127
127
|
process.exit(1);
|
|
128
128
|
}
|
|
129
129
|
return apiAction(async (client) => {
|
|
@@ -132,7 +132,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
132
132
|
console.log(JSON.stringify(result, null, 2));
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
|
-
console.log(
|
|
135
|
+
console.log(success('Attachment deleted.'));
|
|
136
136
|
}
|
|
137
137
|
})(rawOpts);
|
|
138
138
|
});
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { danger, success, warning, muted, highlight } from './ui/theme.js';
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
3
|
import { clearStoredCredentials, requireAuth, getProfile, setProfile, removeProfile, getActiveLabel, setActiveLabel, listProfiles, findLabelByApiKey, resolvedAuthSource, } from '../core/auth/index.js';
|
|
4
4
|
import { JazClient } from '../core/api/client.js';
|
|
@@ -26,7 +26,7 @@ async function validateKey(apiKey) {
|
|
|
26
26
|
/** Shared add-org logic used by both `auth add` and `auth set-key`. */
|
|
27
27
|
async function addOrg(key, opts) {
|
|
28
28
|
if (!key.startsWith('jk-')) {
|
|
29
|
-
console.error(
|
|
29
|
+
console.error(danger('Error: API key must start with "jk-"'));
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
// Check for duplicate key under the same (or default) label
|
|
@@ -36,7 +36,7 @@ async function addOrg(key, opts) {
|
|
|
36
36
|
console.log(JSON.stringify({ error: 'duplicate', existingLabel }));
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
|
-
console.error(
|
|
39
|
+
console.error(warning(`This key is already registered as '${existingLabel}'.`));
|
|
40
40
|
}
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
@@ -46,14 +46,14 @@ async function addOrg(key, opts) {
|
|
|
46
46
|
org = await validateKey(key);
|
|
47
47
|
}
|
|
48
48
|
catch {
|
|
49
|
-
console.error(
|
|
49
|
+
console.error(danger('Error: API key is invalid or the API is unreachable.'));
|
|
50
50
|
process.exit(2);
|
|
51
51
|
}
|
|
52
52
|
const label = opts.as ?? slugify(org.name);
|
|
53
53
|
// Warn if same key exists under different label
|
|
54
54
|
if (existingLabel && existingLabel !== label) {
|
|
55
55
|
if (!opts.json) {
|
|
56
|
-
console.error(
|
|
56
|
+
console.error(warning(`Note: This key is also registered as '${existingLabel}'.`));
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
// Overwrite protection — don't silently replace a different key under the same label
|
|
@@ -63,7 +63,7 @@ async function addOrg(key, opts) {
|
|
|
63
63
|
console.log(JSON.stringify({ error: 'label_taken', label, existingOrgName: existingProfile.orgName }));
|
|
64
64
|
}
|
|
65
65
|
else {
|
|
66
|
-
console.error(
|
|
66
|
+
console.error(danger(`Label '${label}' is already used by ${existingProfile.orgName}. Use --as <label> to choose a different label.`));
|
|
67
67
|
}
|
|
68
68
|
process.exit(1);
|
|
69
69
|
}
|
|
@@ -80,10 +80,10 @@ async function addOrg(key, opts) {
|
|
|
80
80
|
console.log(JSON.stringify({ registered: true, label, orgName: org.name, currency: org.currency, country: org.countryCode }));
|
|
81
81
|
}
|
|
82
82
|
else {
|
|
83
|
-
console.log(
|
|
83
|
+
console.log(success(`\u2713 Registered: ${label} \u2014 ${org.name} (${org.currency}, ${org.countryCode})`));
|
|
84
84
|
const active = getActiveLabel();
|
|
85
85
|
if (active === label) {
|
|
86
|
-
console.log(
|
|
86
|
+
console.log(muted(` Active org set to ${label}`));
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -108,18 +108,18 @@ export function registerAuthCommand(program) {
|
|
|
108
108
|
const orgs = listProfiles();
|
|
109
109
|
const labels = Object.keys(orgs);
|
|
110
110
|
if (labels.length === 0) {
|
|
111
|
-
console.error(
|
|
111
|
+
console.error(danger('No orgs registered. Run `clio auth add <key>` first.'));
|
|
112
112
|
process.exit(1);
|
|
113
113
|
}
|
|
114
114
|
let target = label;
|
|
115
115
|
// Interactive picker if no label provided
|
|
116
116
|
if (!target) {
|
|
117
117
|
if (opts.json || opts.export) {
|
|
118
|
-
console.error(
|
|
118
|
+
console.error(danger('Error: --json and --export require a label argument.'));
|
|
119
119
|
process.exit(1);
|
|
120
120
|
}
|
|
121
121
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
122
|
-
console.error(
|
|
122
|
+
console.error(danger('Error: interactive picker requires a TTY. Provide a label argument.'));
|
|
123
123
|
process.exit(1);
|
|
124
124
|
}
|
|
125
125
|
const active = getActiveLabel();
|
|
@@ -138,7 +138,7 @@ export function registerAuthCommand(program) {
|
|
|
138
138
|
setActiveLabel(target);
|
|
139
139
|
}
|
|
140
140
|
catch (err) {
|
|
141
|
-
console.error(
|
|
141
|
+
console.error(danger(err.message));
|
|
142
142
|
process.exit(1);
|
|
143
143
|
}
|
|
144
144
|
const entry = orgs[target];
|
|
@@ -151,10 +151,10 @@ export function registerAuthCommand(program) {
|
|
|
151
151
|
console.log(JSON.stringify({ switched: true, label: target, orgName: entry.orgName, currency: entry.currency }));
|
|
152
152
|
}
|
|
153
153
|
else {
|
|
154
|
-
console.log(
|
|
154
|
+
console.log(success(`Switched to: ${target} \u2014 ${entry.orgName} (${entry.currency}, ${entry.country})`));
|
|
155
155
|
if (labels.length > 1) {
|
|
156
|
-
console.log(
|
|
157
|
-
console.log(
|
|
156
|
+
console.log(muted(` Tip: Pin to this terminal: eval "$(clio auth switch ${target} --export)"`));
|
|
157
|
+
console.log(muted(` Or add shell integration: eval "$(clio auth shell-init)"`));
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
});
|
|
@@ -199,13 +199,13 @@ export function registerAuthCommand(program) {
|
|
|
199
199
|
}
|
|
200
200
|
const labels = Object.keys(orgs);
|
|
201
201
|
if (labels.length === 0) {
|
|
202
|
-
console.error(
|
|
202
|
+
console.error(warning('No orgs registered. Run `clio auth add <key>` to get started.'));
|
|
203
203
|
return;
|
|
204
204
|
}
|
|
205
205
|
for (const label of labels) {
|
|
206
206
|
const entry = orgs[label];
|
|
207
|
-
const marker = label === active ?
|
|
208
|
-
const labelStr = label === active ?
|
|
207
|
+
const marker = label === active ? warning('\u2605') : ' ';
|
|
208
|
+
const labelStr = label === active ? highlight(label) : label;
|
|
209
209
|
const countryStr = entry.country ? ` ${entry.country}` : '';
|
|
210
210
|
console.log(` ${marker} ${labelStr.padEnd(18)} ${entry.orgName.padEnd(22)} ${entry.currency}${countryStr}`);
|
|
211
211
|
}
|
|
@@ -213,7 +213,7 @@ export function registerAuthCommand(program) {
|
|
|
213
213
|
const pinnedOrg = process.env.JAZ_ORG;
|
|
214
214
|
if (pinnedOrg) {
|
|
215
215
|
const safe = pinnedOrg.replace(/[\x00-\x1F\x7F]/g, '');
|
|
216
|
-
console.log(
|
|
216
|
+
console.log(muted(`\n This terminal is pinned to: ${safe} (via JAZ_ORG)`));
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
219
|
// ── clio auth remove <label> ────────────────────────────────────
|
|
@@ -227,17 +227,17 @@ export function registerAuthCommand(program) {
|
|
|
227
227
|
const orgs = listProfiles();
|
|
228
228
|
const available = Object.keys(orgs);
|
|
229
229
|
const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
|
|
230
|
-
console.error(
|
|
230
|
+
console.error(danger(`Org '${label}' not found.${hint}`));
|
|
231
231
|
process.exit(1);
|
|
232
232
|
}
|
|
233
233
|
if (opts.json) {
|
|
234
234
|
console.log(JSON.stringify({ removed: true, label }));
|
|
235
235
|
}
|
|
236
236
|
else {
|
|
237
|
-
console.log(
|
|
237
|
+
console.log(success(`Removed: ${label}`));
|
|
238
238
|
const active = getActiveLabel();
|
|
239
239
|
if (!active) {
|
|
240
|
-
console.error(
|
|
240
|
+
console.error(warning('No active org. Run `clio auth switch <label>` to set one.'));
|
|
241
241
|
}
|
|
242
242
|
}
|
|
243
243
|
});
|
|
@@ -255,7 +255,7 @@ export function registerAuthCommand(program) {
|
|
|
255
255
|
if (!entry) {
|
|
256
256
|
const available = Object.keys(listProfiles());
|
|
257
257
|
const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
|
|
258
|
-
console.error(
|
|
258
|
+
console.error(danger(`Org '${opts.org}' not found.${hint}`));
|
|
259
259
|
process.exit(1);
|
|
260
260
|
}
|
|
261
261
|
if (opts.json) {
|
|
@@ -276,14 +276,14 @@ export function registerAuthCommand(program) {
|
|
|
276
276
|
}
|
|
277
277
|
else {
|
|
278
278
|
if (active) {
|
|
279
|
-
console.log(
|
|
279
|
+
console.log(highlight('Label:'), active);
|
|
280
280
|
}
|
|
281
|
-
console.log(
|
|
282
|
-
console.log(
|
|
283
|
-
console.log(
|
|
284
|
-
console.log(
|
|
281
|
+
console.log(highlight('Organization:'), org.name);
|
|
282
|
+
console.log(highlight('Currency:'), org.currency);
|
|
283
|
+
console.log(highlight('Country:'), org.countryCode);
|
|
284
|
+
console.log(highlight('Status:'), org.status);
|
|
285
285
|
if (org.lockDate) {
|
|
286
|
-
console.log(
|
|
286
|
+
console.log(highlight('Lock Date:'), org.lockDate);
|
|
287
287
|
}
|
|
288
288
|
if (source) {
|
|
289
289
|
const sourceHuman = {
|
|
@@ -295,13 +295,13 @@ export function registerAuthCommand(program) {
|
|
|
295
295
|
};
|
|
296
296
|
const isPinned = source === 'env-org' || source === 'flag-org' || source === 'flag-api-key' || source === 'env-api-key';
|
|
297
297
|
const sourceStr = sourceHuman[source] ?? source;
|
|
298
|
-
console.log(
|
|
298
|
+
console.log(highlight('Source:'), isPinned ? success(sourceStr) : warning(sourceStr));
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
302
|
catch (err) {
|
|
303
303
|
const isAuthError = err.name === 'AuthError';
|
|
304
|
-
console.error(
|
|
304
|
+
console.error(danger(`Error: ${err.message}`));
|
|
305
305
|
process.exit(isAuthError ? 3 : 2);
|
|
306
306
|
}
|
|
307
307
|
});
|
|
@@ -323,10 +323,10 @@ export function registerAuthCommand(program) {
|
|
|
323
323
|
console.log(JSON.stringify({ removed }));
|
|
324
324
|
}
|
|
325
325
|
else if (removed) {
|
|
326
|
-
console.log(
|
|
326
|
+
console.log(success('All credentials removed.'));
|
|
327
327
|
}
|
|
328
328
|
else {
|
|
329
|
-
console.error(
|
|
329
|
+
console.error(warning('No credentials file found.'));
|
|
330
330
|
}
|
|
331
331
|
});
|
|
332
332
|
// ── clio auth shell-init ────────────────────────────────────────
|
|
@@ -348,20 +348,20 @@ export function registerAuthCommand(program) {
|
|
|
348
348
|
}
|
|
349
349
|
if (process.env.JAZ_ORG) {
|
|
350
350
|
const safe = process.env.JAZ_ORG.replace(/[\x00-\x1F\x7F]/g, '');
|
|
351
|
-
console.log(
|
|
352
|
-
console.log(
|
|
353
|
-
console.log(
|
|
351
|
+
console.log(success(`Session is pinned to: ${safe}`));
|
|
352
|
+
console.log(muted(' To unpin: eval "$(clio auth unpin --export)"'));
|
|
353
|
+
console.log(muted(' Or simply: unset JAZ_ORG'));
|
|
354
354
|
}
|
|
355
355
|
else {
|
|
356
|
-
console.log(
|
|
356
|
+
console.log(muted('Session is not pinned (JAZ_ORG is not set).'));
|
|
357
357
|
}
|
|
358
358
|
});
|
|
359
359
|
}
|
|
360
360
|
function printProfile(label, entry) {
|
|
361
|
-
console.log(
|
|
362
|
-
console.log(
|
|
363
|
-
console.log(
|
|
364
|
-
console.log(
|
|
361
|
+
console.log(highlight('Label:'), label);
|
|
362
|
+
console.log(highlight('Organization:'), entry.orgName);
|
|
363
|
+
console.log(highlight('Currency:'), entry.currency);
|
|
364
|
+
console.log(highlight('Country:'), entry.country);
|
|
365
365
|
}
|
|
366
366
|
/** Generate shell function for session auto-pinning. Works in bash and zsh. */
|
|
367
367
|
function generateShellInit() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { danger, success, muted, highlight } from './ui/theme.js';
|
|
2
2
|
import { listBankRules, getBankRule, searchBankRules, createBankRule, updateBankRule, deleteBankRule, } from '../core/api/bank-rules.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
4
|
import { outputList } from './output.js';
|
|
@@ -44,9 +44,9 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
44
44
|
console.log(JSON.stringify(res.data, null, 2));
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
console.log(
|
|
48
|
-
console.log(
|
|
49
|
-
console.log(
|
|
47
|
+
console.log(highlight('Name:'), res.data.name);
|
|
48
|
+
console.log(highlight('Action:'), res.data.actionType);
|
|
49
|
+
console.log(highlight('ID:'), res.data.resourceId);
|
|
50
50
|
})(opts));
|
|
51
51
|
cmd
|
|
52
52
|
.command('search <query>')
|
|
@@ -81,8 +81,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
81
81
|
let body = readBodyInput(opts);
|
|
82
82
|
if (!body) {
|
|
83
83
|
if (!opts.name || !opts.account) {
|
|
84
|
-
console.error(
|
|
85
|
-
console.error(
|
|
84
|
+
console.error(danger('Required: --name, --account'));
|
|
85
|
+
console.error(muted('Or use --input <file> to provide full JSON body.'));
|
|
86
86
|
process.exit(1);
|
|
87
87
|
}
|
|
88
88
|
body = {
|
|
@@ -94,7 +94,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
94
94
|
body.configuration = JSON.parse(opts.config);
|
|
95
95
|
}
|
|
96
96
|
catch {
|
|
97
|
-
console.error(
|
|
97
|
+
console.error(danger('Invalid --config JSON'));
|
|
98
98
|
process.exit(1);
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -105,8 +105,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
105
105
|
console.log(JSON.stringify(res.data, null, 2));
|
|
106
106
|
return;
|
|
107
107
|
}
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(
|
|
108
|
+
console.log(success('Bank rule created.'));
|
|
109
|
+
console.log(highlight('ID:'), res.data.resourceId);
|
|
110
110
|
}));
|
|
111
111
|
cmd
|
|
112
112
|
.command('update <resourceId>')
|
|
@@ -130,8 +130,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
130
130
|
// appliesToReconciliationAccount as an object (not UUID), so we can't
|
|
131
131
|
// round-trip it. Require the UUID explicitly.
|
|
132
132
|
if (!opts.account) {
|
|
133
|
-
console.error(
|
|
134
|
-
console.error(
|
|
133
|
+
console.error(danger('--account is required for update (PUT is full replacement — GET does not return the UUID)'));
|
|
134
|
+
console.error(muted('Use: clio bank-rules update <id> --account <bank-account-uuid> [--name ...] [--config ...]'));
|
|
135
135
|
process.exitCode = 1;
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
@@ -148,7 +148,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
148
148
|
data.configuration = JSON.parse(opts.config);
|
|
149
149
|
}
|
|
150
150
|
catch {
|
|
151
|
-
console.error(
|
|
151
|
+
console.error(danger('Invalid --config JSON'));
|
|
152
152
|
process.exit(1);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
@@ -159,7 +159,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
159
159
|
console.log(JSON.stringify(res.data, null, 2));
|
|
160
160
|
return;
|
|
161
161
|
}
|
|
162
|
-
console.log(
|
|
162
|
+
console.log(success(`Bank rule ${resourceId} updated.`));
|
|
163
163
|
})(opts));
|
|
164
164
|
cmd
|
|
165
165
|
.command('delete <resourceId>')
|
|
@@ -173,6 +173,6 @@ Strings are replaced with actual bank record values during reconciliation.`);
|
|
|
173
173
|
console.log(JSON.stringify({ deleted: true, resourceId }));
|
|
174
174
|
return;
|
|
175
175
|
}
|
|
176
|
-
console.log(
|
|
176
|
+
console.log(success(`Bank rule ${resourceId} deleted.`));
|
|
177
177
|
})(opts));
|
|
178
178
|
}
|
package/dist/commands/bank.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { danger, success, accent, warning, muted, highlight } from './ui/theme.js';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { basename, extname, resolve } from 'node:path';
|
|
4
4
|
import { listBankAccounts, getBankAccount, searchBankRecords, addBankRecords, importBankStatement, } from '../core/api/bank.js';
|
|
@@ -31,9 +31,9 @@ export function registerBankCommand(program) {
|
|
|
31
31
|
console.log(JSON.stringify(res, null, 2));
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
console.log(
|
|
34
|
+
console.log(highlight(`Bank Accounts (${res.data.length}):\n`));
|
|
35
35
|
for (const a of res.data) {
|
|
36
|
-
console.log(` ${
|
|
36
|
+
console.log(` ${accent(a.resourceId)} ${a.name} ${muted(a.currencyCode)} ${a.status}`);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}));
|
|
@@ -51,11 +51,11 @@ export function registerBankCommand(program) {
|
|
|
51
51
|
console.log(JSON.stringify(a, null, 2));
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
|
-
console.log(
|
|
55
|
-
console.log(
|
|
56
|
-
console.log(
|
|
57
|
-
console.log(
|
|
58
|
-
console.log(
|
|
54
|
+
console.log(highlight('Name:'), a.name);
|
|
55
|
+
console.log(highlight('ID:'), a.resourceId);
|
|
56
|
+
console.log(highlight('Account ID:'), a.accountResourceId);
|
|
57
|
+
console.log(highlight('Currency:'), a.currencyCode);
|
|
58
|
+
console.log(highlight('Status:'), a.status);
|
|
59
59
|
}
|
|
60
60
|
})(opts));
|
|
61
61
|
// ── clio bank records ───────────────────────────────────────────
|
|
@@ -99,14 +99,14 @@ export function registerBankCommand(program) {
|
|
|
99
99
|
console.log('No records found.');
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
console.log(
|
|
102
|
+
console.log(highlight(`Bank Records (${res.data.length} of ${res.totalElements}):\n`));
|
|
103
103
|
for (const r of res.data) {
|
|
104
104
|
const net = typeof r.netAmount === 'number' && Number.isFinite(r.netAmount) ? r.netAmount : 0;
|
|
105
105
|
const amount = net >= 0
|
|
106
|
-
?
|
|
107
|
-
:
|
|
108
|
-
const payer = r.extContactName ? ` ${
|
|
109
|
-
console.log(` ${
|
|
106
|
+
? success(`+${net.toFixed(2)}`)
|
|
107
|
+
: danger(net.toFixed(2));
|
|
108
|
+
const payer = r.extContactName ? ` ${muted(r.extContactName)}` : '';
|
|
109
|
+
console.log(` ${accent(r.resourceId)} ${r.valueDate} ${amount} ${r.description ?? ''}${payer} ${muted(r.status)}`);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
})(opts));
|
|
@@ -139,12 +139,12 @@ export function registerBankCommand(program) {
|
|
|
139
139
|
}
|
|
140
140
|
else {
|
|
141
141
|
if (errors.length > 0) {
|
|
142
|
-
console.log(
|
|
142
|
+
console.log(danger(`${errors.length} error(s):`));
|
|
143
143
|
for (const e of errors)
|
|
144
|
-
console.log(` ${
|
|
144
|
+
console.log(` ${danger(String(e))}`);
|
|
145
145
|
}
|
|
146
146
|
else {
|
|
147
|
-
console.log(
|
|
147
|
+
console.log(success(`Created ${parsed.length} bank record(s).`));
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
})(opts));
|
|
@@ -161,8 +161,8 @@ export function registerBankCommand(program) {
|
|
|
161
161
|
.action(apiAction(async (client, opts) => {
|
|
162
162
|
const recType = opts.type.toUpperCase();
|
|
163
163
|
if (!RECON_TYPES.includes(recType)) {
|
|
164
|
-
console.error(
|
|
165
|
-
console.error(
|
|
164
|
+
console.error(danger(`Invalid --type: ${recType}`));
|
|
165
|
+
console.error(muted(`Valid types: ${RECON_TYPES.join(', ')}`));
|
|
166
166
|
process.exit(1);
|
|
167
167
|
}
|
|
168
168
|
try {
|
|
@@ -176,16 +176,16 @@ export function registerBankCommand(program) {
|
|
|
176
176
|
else {
|
|
177
177
|
const data = res.data;
|
|
178
178
|
const count = Array.isArray(data) ? data.length : 0;
|
|
179
|
-
console.log(
|
|
179
|
+
console.log(highlight(`Auto-Reconciliation Suggestions (${recType}): ${count} found\n`));
|
|
180
180
|
if (Array.isArray(data)) {
|
|
181
181
|
for (const item of data.slice(0, 50)) {
|
|
182
182
|
const r = item;
|
|
183
183
|
const desc = r.description ?? r.bankRecordDescription ?? '';
|
|
184
|
-
const amount = typeof r.amount === 'number' ?
|
|
185
|
-
console.log(` ${
|
|
184
|
+
const amount = typeof r.amount === 'number' ? muted(` $${r.amount.toFixed(2)}`) : '';
|
|
185
|
+
console.log(` ${accent(String(r.bankRecordResourceId ?? r.resourceId ?? '?'))} ${desc}${amount}`);
|
|
186
186
|
}
|
|
187
187
|
if (data.length > 50)
|
|
188
|
-
console.log(
|
|
188
|
+
console.log(muted(` ... and ${data.length - 50} more (use --json for full output)`));
|
|
189
189
|
}
|
|
190
190
|
else {
|
|
191
191
|
console.log(JSON.stringify(res, null, 2));
|
|
@@ -195,7 +195,7 @@ export function registerBankCommand(program) {
|
|
|
195
195
|
catch (e) {
|
|
196
196
|
const status = e.status ?? e.response?.status;
|
|
197
197
|
if (status === 404) {
|
|
198
|
-
console.error(
|
|
198
|
+
console.error(warning('Auto-reconciliation endpoint not available on this server.'));
|
|
199
199
|
process.exit(1);
|
|
200
200
|
}
|
|
201
201
|
throw e;
|
|
@@ -215,7 +215,7 @@ export function registerBankCommand(program) {
|
|
|
215
215
|
const ext = extname(filePath).toLowerCase();
|
|
216
216
|
const mime = BANK_MIME_MAP[ext];
|
|
217
217
|
if (!mime) {
|
|
218
|
-
console.error(
|
|
218
|
+
console.error(danger(`Error: unsupported file type "${ext}". Supported: ${Object.keys(BANK_MIME_MAP).join(', ')}`));
|
|
219
219
|
process.exit(1);
|
|
220
220
|
}
|
|
221
221
|
const buffer = readFileSync(filePath);
|
|
@@ -231,9 +231,9 @@ export function registerBankCommand(program) {
|
|
|
231
231
|
console.log(JSON.stringify(res.data, null, 2));
|
|
232
232
|
}
|
|
233
233
|
else {
|
|
234
|
-
console.log(
|
|
235
|
-
console.log(
|
|
236
|
-
console.log(
|
|
234
|
+
console.log(success('Bank statement uploaded — processing started.'));
|
|
235
|
+
console.log(highlight('File:'), fileName);
|
|
236
|
+
console.log(muted('Check status: clio magic search --type bank-statement'));
|
|
237
237
|
}
|
|
238
238
|
}));
|
|
239
239
|
}
|