@aderis-erp/cli 1.1.3 → 1.1.5
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 +1 -0
- package/dist/commands/access-groups.js +42 -8
- package/dist/commands/account-transaction-allocations.js +38 -4
- package/dist/commands/account-transactions.d.ts +2 -0
- package/dist/commands/account-transactions.js +68 -32
- package/dist/commands/accounts.js +46 -12
- package/dist/commands/agent-platform.js +37 -3
- package/dist/commands/agent-runs.js +49 -15
- package/dist/commands/analytics.js +39 -5
- package/dist/commands/api-clients.d.ts +58 -0
- package/dist/commands/api-clients.js +1375 -0
- package/dist/commands/api-keys.js +40 -6
- package/dist/commands/async-jobs.js +45 -11
- package/dist/commands/audit-log.js +38 -4
- package/dist/commands/bank-accounts.js +54 -20
- package/dist/commands/bank-integrations.js +56 -22
- package/dist/commands/business-partners.js +77 -43
- package/dist/commands/chat.js +43 -9
- package/dist/commands/credit-card-accounts.d.ts +4 -0
- package/dist/commands/credit-card-accounts.js +64 -25
- package/dist/commands/currencies.d.ts +56 -0
- package/dist/commands/currencies.js +1361 -0
- package/dist/commands/custody-accounts.d.ts +56 -0
- package/dist/commands/custody-accounts.js +1369 -0
- package/dist/commands/{integration-identities.d.ts → dashboards.d.ts} +3 -3
- package/dist/commands/dashboards.js +1381 -0
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +57 -0
- package/dist/commands/{integration-identities.js → document-checksums.js} +48 -21
- package/dist/commands/dunning-configs.js +41 -7
- package/dist/commands/dunning-reminders.js +44 -10
- package/dist/commands/dunning-runs.js +37 -3
- package/dist/commands/email-transactions.js +39 -5
- package/dist/commands/employees.js +77 -43
- package/dist/commands/entity-configurations.js +39 -5
- package/dist/commands/event-mapping-rules.js +37 -3
- package/dist/commands/event-processor-mappings.js +41 -7
- package/dist/commands/files.js +48 -14
- package/dist/commands/financial-instrument-transactions.d.ts +56 -0
- package/dist/commands/financial-instrument-transactions.js +1369 -0
- package/dist/commands/financial-instrument-types.d.ts +56 -0
- package/dist/commands/financial-instrument-types.js +1369 -0
- package/dist/commands/financial-instruments.d.ts +56 -0
- package/dist/commands/financial-instruments.js +1369 -0
- package/dist/commands/health.js +41 -7
- package/dist/commands/imports.js +39 -5
- package/dist/commands/inbox.js +42 -8
- package/dist/commands/integrations.js +39 -5
- package/dist/commands/item-categories.js +41 -7
- package/dist/commands/items.js +42 -8
- package/dist/commands/journal-lines.js +37 -3
- package/dist/commands/journals.js +61 -27
- package/dist/commands/{workflows.d.ts → kpis.d.ts} +1 -1
- package/dist/commands/kpis.js +1371 -0
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.d.ts +56 -0
- package/dist/commands/notifications.js +1360 -0
- package/dist/commands/office-locations.js +41 -7
- package/dist/commands/payment-methods.js +46 -12
- package/dist/commands/payment-runs.js +54 -20
- package/dist/commands/payment-terms.js +42 -8
- package/dist/commands/payments.js +43 -9
- package/dist/commands/payroll-runs.js +71 -37
- package/dist/commands/permissions.js +37 -3
- package/dist/commands/price-lists.js +48 -14
- package/dist/commands/processor-mappings.js +40 -6
- package/dist/commands/processors.js +46 -12
- package/dist/commands/purchase-order-types.js +41 -7
- package/dist/commands/purchase-orders.js +60 -26
- package/dist/commands/reports.js +43 -8
- package/dist/commands/roles.js +40 -6
- package/dist/commands/salary-types.js +41 -7
- package/dist/commands/sales-invoices.js +85 -51
- package/dist/commands/sales-orders.js +69 -35
- package/dist/commands/saved-views.js +39 -5
- package/dist/commands/scheduled-processor-mappings.js +41 -7
- package/dist/commands/schedules.js +45 -11
- package/dist/commands/settings.d.ts +56 -0
- package/dist/commands/settings.js +1361 -0
- package/dist/commands/tags.js +42 -8
- package/dist/commands/tax-codes.js +44 -10
- package/dist/commands/tax-matrix.js +41 -7
- package/dist/commands/templates.js +50 -15
- package/dist/commands/tenants.js +44 -10
- package/dist/commands/tools.js +38 -4
- package/dist/commands/users.js +58 -24
- package/dist/commands/vat-declarations.js +61 -27
- package/dist/commands/vendor-invoices.js +82 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.d.ts +56 -0
- package/dist/commands/{workflows.js → work-summary.js} +49 -18
- package/dist/lib/auth/index.js +5 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.d.ts +42 -0
- package/dist/lib/production-guard.js +94 -0
- package/oclif.manifest.json +2142 -333
- package/package.json +9 -3
package/dist/commands/items.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,12 +12,12 @@ const SERVER_IMPORTS = ["import"];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "import"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/items', summary: 'Get all items with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/items/{id}', summary: 'Get an item by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/items/{id}', summary: 'Delete an item', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'import': { method: 'POST', path: '/v1/items/import', summary: 'Import items', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/items', summary: 'Get all items with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['replacedByIds', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/items/{id}', summary: 'Get an item by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['replacedByIds', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/items/{id}', summary: 'Delete an item', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'import': { method: 'POST', path: '/v1/items/import', summary: 'Import items', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
21
|
};
|
|
21
22
|
export default class Items extends Command {
|
|
22
23
|
static description = 'Manage items';
|
|
@@ -38,7 +39,7 @@ export default class Items extends Command {
|
|
|
38
39
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
39
40
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
40
41
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
41
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
42
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
42
43
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
43
44
|
mode: Flags.string({ description: 'Import mode: upsert (default) creates, updates or skips each record; create refuses records that already exist; update refuses records that do not', options: ['upsert', 'create', 'update'] }),
|
|
44
45
|
reference: Flags.string({ description: 'Caller-defined text stored on the import run, for tracking and filtering' }),
|
|
@@ -173,6 +174,17 @@ export default class Items extends Command {
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
}
|
|
177
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
178
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
179
|
+
for (const param of endpoint.specParams) {
|
|
180
|
+
const value = flags[param.flag];
|
|
181
|
+
if (value === undefined || value === '') {
|
|
182
|
+
if (param.required)
|
|
183
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
queryParams[param.name] = value;
|
|
187
|
+
}
|
|
176
188
|
let data;
|
|
177
189
|
if (endpoint.isMultipart) {
|
|
178
190
|
if (!flags.file)
|
|
@@ -193,6 +205,25 @@ export default class Items extends Command {
|
|
|
193
205
|
}
|
|
194
206
|
data = form;
|
|
195
207
|
}
|
|
208
|
+
else if (endpoint.bodyMediaType) {
|
|
209
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
210
|
+
// verbatim, under the content type the endpoint asks for.
|
|
211
|
+
if (flags.file) {
|
|
212
|
+
const fsModule = await import('node:fs');
|
|
213
|
+
try {
|
|
214
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (flags.data) {
|
|
221
|
+
data = flags.data;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
196
227
|
else if (endpoint.hasBody) {
|
|
197
228
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
198
229
|
// input file — skip the read-as-body branch.
|
|
@@ -288,7 +319,7 @@ export default class Items extends Command {
|
|
|
288
319
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
289
320
|
}
|
|
290
321
|
else if (data) {
|
|
291
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
322
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
292
323
|
}
|
|
293
324
|
process.stderr.write('\n');
|
|
294
325
|
}
|
|
@@ -302,6 +333,7 @@ export default class Items extends Command {
|
|
|
302
333
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
303
334
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
304
335
|
data,
|
|
336
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
305
337
|
contextName: flags.context,
|
|
306
338
|
binary: true,
|
|
307
339
|
});
|
|
@@ -327,6 +359,7 @@ export default class Items extends Command {
|
|
|
327
359
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
328
360
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
329
361
|
data,
|
|
362
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
330
363
|
contextName: flags.context,
|
|
331
364
|
binary: true,
|
|
332
365
|
});
|
|
@@ -347,6 +380,7 @@ export default class Items extends Command {
|
|
|
347
380
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
348
381
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
349
382
|
data,
|
|
383
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
350
384
|
contextName: flags.context,
|
|
351
385
|
acceptAny: true,
|
|
352
386
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,7 +12,7 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/journal-lines', summary: 'List all journal lines (global view across all journals)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/journal-lines', summary: 'List all journal lines (global view across all journals)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
15
16
|
};
|
|
16
17
|
export default class JournalLines extends Command {
|
|
17
18
|
static description = 'Manage journal lines';
|
|
@@ -29,7 +30,7 @@ export default class JournalLines extends Command {
|
|
|
29
30
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
30
31
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
31
32
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
32
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
33
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
33
34
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
34
35
|
page: Flags.string({ description: 'Page number' }),
|
|
35
36
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -160,6 +161,17 @@ export default class JournalLines extends Command {
|
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
}
|
|
164
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
165
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
166
|
+
for (const param of endpoint.specParams) {
|
|
167
|
+
const value = flags[param.flag];
|
|
168
|
+
if (value === undefined || value === '') {
|
|
169
|
+
if (param.required)
|
|
170
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
queryParams[param.name] = value;
|
|
174
|
+
}
|
|
163
175
|
let data;
|
|
164
176
|
if (endpoint.isMultipart) {
|
|
165
177
|
if (!flags.file)
|
|
@@ -180,6 +192,25 @@ export default class JournalLines extends Command {
|
|
|
180
192
|
}
|
|
181
193
|
data = form;
|
|
182
194
|
}
|
|
195
|
+
else if (endpoint.bodyMediaType) {
|
|
196
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
197
|
+
// verbatim, under the content type the endpoint asks for.
|
|
198
|
+
if (flags.file) {
|
|
199
|
+
const fsModule = await import('node:fs');
|
|
200
|
+
try {
|
|
201
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (flags.data) {
|
|
208
|
+
data = flags.data;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
183
214
|
else if (endpoint.hasBody) {
|
|
184
215
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
185
216
|
// input file — skip the read-as-body branch.
|
|
@@ -275,7 +306,7 @@ export default class JournalLines extends Command {
|
|
|
275
306
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
276
307
|
}
|
|
277
308
|
else if (data) {
|
|
278
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
309
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
279
310
|
}
|
|
280
311
|
process.stderr.write('\n');
|
|
281
312
|
}
|
|
@@ -289,6 +320,7 @@ export default class JournalLines extends Command {
|
|
|
289
320
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
290
321
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
291
322
|
data,
|
|
323
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
292
324
|
contextName: flags.context,
|
|
293
325
|
binary: true,
|
|
294
326
|
});
|
|
@@ -314,6 +346,7 @@ export default class JournalLines extends Command {
|
|
|
314
346
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
315
347
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
316
348
|
data,
|
|
349
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
317
350
|
contextName: flags.context,
|
|
318
351
|
binary: true,
|
|
319
352
|
});
|
|
@@ -334,6 +367,7 @@ export default class JournalLines extends Command {
|
|
|
334
367
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
335
368
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
336
369
|
data,
|
|
370
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
337
371
|
contextName: flags.context,
|
|
338
372
|
acceptAny: true,
|
|
339
373
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,31 +12,31 @@ const SERVER_IMPORTS = ["import"];
|
|
|
11
12
|
const NESTED_UPSERTS = ["notes", "files"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "stats", "get", "update", "delete", "post", "approve", "cancel", "reverse", "update-lines", "get-deferrals", "create-deferrals", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "import"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/journals', summary: 'List all journals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines', 'files', 'notes'] },
|
|
16
|
-
'stats': { method: 'GET', path: '/v1/journals/stats', summary: 'Journal counts and debit totals per date range', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'get': { method: 'GET', path: '/v1/journals/{id}', summary: 'Get a journal by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'] },
|
|
19
|
-
'delete': { method: 'DELETE', path: '/v1/journals/{id}', summary: 'Delete a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'post': { method: 'POST', path: '/v1/journals/{id}/post', summary: 'Post journal (finalize)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'approve': { method: 'POST', path: '/v1/journals/{id}/approve', summary: 'Approve a journal (transitions DRAFT to APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'cancel': { method: 'POST', path: '/v1/journals/{id}/cancel', summary: 'Cancel a journal', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'reverse': { method: 'POST', path: '/v1/journals/{id}/reverse', summary: 'Reverse a posted journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'update-lines': { method: 'PATCH', path: '/v1/journals/{id}/lines/{lineId}', summary: 'Update a single journal line in place', pathParams: ['id', 'lineId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
|
|
25
|
-
'get-deferrals': { method: 'GET', path: '/v1/journals/{id}/deferrals', summary: 'List the deferral schedules of a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'create-deferrals': { method: 'POST', path: '/v1/journals/{id}/deferrals', summary: 'Create deferral schedules for one line of a journal (manual trigger)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['periods'] },
|
|
27
|
-
'list-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes', summary: 'Get all notes for a journal', pathParams: ['journalId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'create-notes': { method: 'POST', path: '/v1/journals/{journalId}/notes', summary: 'Create a note for a journal', pathParams: ['journalId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'get-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Get a specific note for a journal', pathParams: ['journalId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'update-notes': { method: 'PATCH', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Update a note for a journal', pathParams: ['journalId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'delete-notes': { method: 'DELETE', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Delete a note from a journal', pathParams: ['journalId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'list-files': { method: 'GET', path: '/v1/journals/{parentId}/files', summary: 'List file attachments for a journal', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'create-files': { method: 'POST', path: '/v1/journals/{parentId}/files', summary: 'Upload a file attachment to a journal', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'get-files': { method: 'GET', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Get a file attachment for a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'update-files': { method: 'PATCH', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a journal', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'delete-files': { method: 'DELETE', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'files-download': { method: 'GET', path: '/v1/journals/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'import': { method: 'POST', path: '/v1/journals/import', summary: 'Import journals', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/journals', summary: 'List all journals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines', 'files', 'notes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'stats': { method: 'GET', path: '/v1/journals/stats', summary: 'Journal counts and debit totals per date range', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'get': { method: 'GET', path: '/v1/journals/{id}', summary: 'Get a journal by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'delete': { method: 'DELETE', path: '/v1/journals/{id}', summary: 'Delete a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'post': { method: 'POST', path: '/v1/journals/{id}/post', summary: 'Post journal (finalize)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'approve': { method: 'POST', path: '/v1/journals/{id}/approve', summary: 'Approve a journal (transitions DRAFT to APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'cancel': { method: 'POST', path: '/v1/journals/{id}/cancel', summary: 'Cancel a journal', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'reverse': { method: 'POST', path: '/v1/journals/{id}/reverse', summary: 'Reverse a posted journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'update-lines': { method: 'PATCH', path: '/v1/journals/{id}/lines/{lineId}', summary: 'Update a single journal line in place', pathParams: ['id', 'lineId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'get-deferrals': { method: 'GET', path: '/v1/journals/{id}/deferrals', summary: 'List the deferral schedules of a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'create-deferrals': { method: 'POST', path: '/v1/journals/{id}/deferrals', summary: 'Create deferral schedules for one line of a journal (manual trigger)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['periods'], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'list-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes', summary: 'Get all notes for a journal', pathParams: ['journalId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'create-notes': { method: 'POST', path: '/v1/journals/{journalId}/notes', summary: 'Create a note for a journal', pathParams: ['journalId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'get-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Get a specific note for a journal', pathParams: ['journalId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'update-notes': { method: 'PATCH', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Update a note for a journal', pathParams: ['journalId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'delete-notes': { method: 'DELETE', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Delete a note from a journal', pathParams: ['journalId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'list-files': { method: 'GET', path: '/v1/journals/{parentId}/files', summary: 'List file attachments for a journal', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'create-files': { method: 'POST', path: '/v1/journals/{parentId}/files', summary: 'Upload a file attachment to a journal', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'get-files': { method: 'GET', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Get a file attachment for a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'update-files': { method: 'PATCH', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a journal', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'delete-files': { method: 'DELETE', path: '/v1/journals/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'files-download': { method: 'GET', path: '/v1/journals/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a journal', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'import': { method: 'POST', path: '/v1/journals/import', summary: 'Import journals', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
40
|
};
|
|
40
41
|
export default class Journals extends Command {
|
|
41
42
|
static description = 'Manage journals';
|
|
@@ -57,7 +58,7 @@ export default class Journals extends Command {
|
|
|
57
58
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
58
59
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
59
60
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
60
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
61
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
61
62
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
62
63
|
mode: Flags.string({ description: 'Import mode: upsert (default) creates, updates or skips each record; create refuses records that already exist; update refuses records that do not', options: ['upsert', 'create', 'update'] }),
|
|
63
64
|
reference: Flags.string({ description: 'Caller-defined text stored on the import run, for tracking and filtering' }),
|
|
@@ -195,6 +196,17 @@ export default class Journals extends Command {
|
|
|
195
196
|
}
|
|
196
197
|
}
|
|
197
198
|
}
|
|
199
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
200
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
201
|
+
for (const param of endpoint.specParams) {
|
|
202
|
+
const value = flags[param.flag];
|
|
203
|
+
if (value === undefined || value === '') {
|
|
204
|
+
if (param.required)
|
|
205
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
queryParams[param.name] = value;
|
|
209
|
+
}
|
|
198
210
|
let data;
|
|
199
211
|
if (endpoint.isMultipart) {
|
|
200
212
|
if (!flags.file)
|
|
@@ -215,6 +227,25 @@ export default class Journals extends Command {
|
|
|
215
227
|
}
|
|
216
228
|
data = form;
|
|
217
229
|
}
|
|
230
|
+
else if (endpoint.bodyMediaType) {
|
|
231
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
232
|
+
// verbatim, under the content type the endpoint asks for.
|
|
233
|
+
if (flags.file) {
|
|
234
|
+
const fsModule = await import('node:fs');
|
|
235
|
+
try {
|
|
236
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else if (flags.data) {
|
|
243
|
+
data = flags.data;
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
218
249
|
else if (endpoint.hasBody) {
|
|
219
250
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
220
251
|
// input file — skip the read-as-body branch.
|
|
@@ -310,7 +341,7 @@ export default class Journals extends Command {
|
|
|
310
341
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
311
342
|
}
|
|
312
343
|
else if (data) {
|
|
313
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
344
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
314
345
|
}
|
|
315
346
|
process.stderr.write('\n');
|
|
316
347
|
}
|
|
@@ -324,6 +355,7 @@ export default class Journals extends Command {
|
|
|
324
355
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
325
356
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
326
357
|
data,
|
|
358
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
327
359
|
contextName: flags.context,
|
|
328
360
|
binary: true,
|
|
329
361
|
});
|
|
@@ -349,6 +381,7 @@ export default class Journals extends Command {
|
|
|
349
381
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
350
382
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
351
383
|
data,
|
|
384
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
352
385
|
contextName: flags.context,
|
|
353
386
|
binary: true,
|
|
354
387
|
});
|
|
@@ -369,6 +402,7 @@ export default class Journals extends Command {
|
|
|
369
402
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
370
403
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
371
404
|
data,
|
|
405
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
372
406
|
contextName: flags.context,
|
|
373
407
|
acceptAny: true,
|
|
374
408
|
});
|