@aderis-erp/cli 1.1.1 → 1.1.2
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/dist/commands/access-groups.d.ts +8 -0
- package/dist/commands/access-groups.js +54 -6
- package/dist/commands/account-transaction-allocations.d.ts +8 -0
- package/dist/commands/account-transaction-allocations.js +52 -5
- package/dist/commands/account-transactions.d.ts +8 -0
- package/dist/commands/account-transactions.js +55 -7
- package/dist/commands/accounts.d.ts +8 -0
- package/dist/commands/accounts.js +52 -5
- package/dist/commands/agent-platform.d.ts +8 -0
- package/dist/commands/agent-platform.js +52 -5
- package/dist/commands/agent-runs.d.ts +8 -0
- package/dist/commands/agent-runs.js +52 -5
- package/dist/commands/analytics.d.ts +8 -0
- package/dist/commands/analytics.js +52 -5
- package/dist/commands/api-keys.d.ts +8 -0
- package/dist/commands/api-keys.js +52 -5
- package/dist/commands/async-jobs.d.ts +8 -0
- package/dist/commands/async-jobs.js +52 -5
- package/dist/commands/audit-log.d.ts +8 -0
- package/dist/commands/audit-log.js +52 -5
- package/dist/commands/bank-accounts.d.ts +8 -0
- package/dist/commands/bank-accounts.js +52 -5
- package/dist/commands/bank-integrations.d.ts +8 -0
- package/dist/commands/bank-integrations.js +52 -5
- package/dist/commands/business-partners.d.ts +9 -0
- package/dist/commands/business-partners.js +64 -7
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.js +52 -5
- package/dist/commands/credit-card-accounts.d.ts +8 -0
- package/dist/commands/credit-card-accounts.js +52 -5
- package/dist/commands/delivery-notes.d.ts +8 -0
- package/dist/commands/delivery-notes.js +52 -5
- package/dist/commands/dunning-configs.d.ts +8 -0
- package/dist/commands/dunning-configs.js +52 -5
- package/dist/commands/dunning-reminders.d.ts +8 -0
- package/dist/commands/dunning-reminders.js +52 -5
- package/dist/commands/dunning-runs.d.ts +8 -0
- package/dist/commands/dunning-runs.js +52 -5
- package/dist/commands/email-transactions.d.ts +8 -0
- package/dist/commands/email-transactions.js +52 -5
- package/dist/commands/employees.d.ts +8 -0
- package/dist/commands/employees.js +52 -5
- package/dist/commands/entity-configurations.d.ts +8 -0
- package/dist/commands/entity-configurations.js +52 -5
- package/dist/commands/event-processor-mappings.d.ts +8 -0
- package/dist/commands/event-processor-mappings.js +52 -5
- package/dist/commands/files.d.ts +8 -0
- package/dist/commands/files.js +52 -5
- package/dist/commands/health.d.ts +8 -0
- package/dist/commands/health.js +52 -5
- package/dist/commands/imports.d.ts +8 -0
- package/dist/commands/imports.js +53 -8
- package/dist/commands/inbox.d.ts +8 -0
- package/dist/commands/inbox.js +53 -7
- package/dist/commands/integration-identities.d.ts +8 -0
- package/dist/commands/integration-identities.js +52 -5
- package/dist/commands/integrations.d.ts +8 -0
- package/dist/commands/integrations.js +52 -5
- package/dist/commands/item-categories.d.ts +8 -0
- package/dist/commands/item-categories.js +52 -5
- package/dist/commands/items.d.ts +8 -0
- package/dist/commands/items.js +52 -5
- package/dist/commands/journal-lines.d.ts +8 -0
- package/dist/commands/journal-lines.js +52 -5
- package/dist/commands/journals.d.ts +8 -0
- package/dist/commands/journals.js +52 -5
- package/dist/commands/ledgers.d.ts +8 -0
- package/dist/commands/ledgers.js +52 -5
- package/dist/commands/my-account.d.ts +8 -0
- package/dist/commands/my-account.js +52 -5
- package/dist/commands/office-locations.d.ts +8 -0
- package/dist/commands/office-locations.js +52 -5
- package/dist/commands/payment-methods.d.ts +8 -0
- package/dist/commands/payment-methods.js +52 -5
- package/dist/commands/payment-runs.d.ts +8 -0
- package/dist/commands/payment-runs.js +54 -6
- package/dist/commands/payment-terms.d.ts +8 -0
- package/dist/commands/payment-terms.js +52 -5
- package/dist/commands/payments.d.ts +8 -0
- package/dist/commands/payments.js +52 -5
- package/dist/commands/payroll-runs.d.ts +8 -0
- package/dist/commands/payroll-runs.js +52 -5
- package/dist/commands/permissions.d.ts +8 -0
- package/dist/commands/permissions.js +52 -5
- package/dist/commands/price-lists.d.ts +8 -0
- package/dist/commands/price-lists.js +52 -5
- package/dist/commands/processor-mappings.d.ts +8 -0
- package/dist/commands/processor-mappings.js +52 -5
- package/dist/commands/processors.d.ts +8 -0
- package/dist/commands/processors.js +52 -5
- package/dist/commands/purchase-order-types.d.ts +8 -0
- package/dist/commands/purchase-order-types.js +52 -5
- package/dist/commands/purchase-orders.d.ts +8 -0
- package/dist/commands/purchase-orders.js +52 -5
- package/dist/commands/reports.d.ts +8 -0
- package/dist/commands/reports.js +52 -5
- package/dist/commands/roles.d.ts +8 -0
- package/dist/commands/roles.js +52 -5
- package/dist/commands/salary-types.d.ts +8 -0
- package/dist/commands/salary-types.js +52 -5
- package/dist/commands/sales-invoices.d.ts +10 -0
- package/dist/commands/sales-invoices.js +62 -6
- package/dist/commands/sales-orders.d.ts +8 -0
- package/dist/commands/sales-orders.js +52 -5
- package/dist/commands/saved-views.d.ts +8 -0
- package/dist/commands/saved-views.js +52 -5
- package/dist/commands/scheduled-processor-mappings.d.ts +8 -0
- package/dist/commands/scheduled-processor-mappings.js +52 -5
- package/dist/commands/schedules.d.ts +8 -0
- package/dist/commands/schedules.js +52 -5
- package/dist/commands/tags.d.ts +8 -0
- package/dist/commands/tags.js +52 -5
- package/dist/commands/tax-codes.d.ts +8 -0
- package/dist/commands/tax-codes.js +52 -5
- package/dist/commands/tax-matrix.d.ts +8 -0
- package/dist/commands/tax-matrix.js +52 -5
- package/dist/commands/templates.d.ts +8 -0
- package/dist/commands/templates.js +52 -5
- package/dist/commands/tenants.d.ts +8 -0
- package/dist/commands/tenants.js +52 -5
- package/dist/commands/tools.d.ts +8 -0
- package/dist/commands/tools.js +52 -5
- package/dist/commands/users.d.ts +8 -0
- package/dist/commands/users.js +52 -5
- package/dist/commands/vat-declarations.d.ts +8 -0
- package/dist/commands/vat-declarations.js +52 -5
- package/dist/commands/vendor-invoices.d.ts +9 -0
- package/dist/commands/vendor-invoices.js +60 -8
- package/dist/commands/webhooks.d.ts +8 -0
- package/dist/commands/webhooks.js +52 -5
- package/dist/commands/workflows.d.ts +8 -0
- package/dist/commands/workflows.js +52 -5
- package/oclif.manifest.json +433 -10
- package/package.json +1 -1
|
@@ -23,6 +23,7 @@ export default class AccessGroups extends Command {
|
|
|
23
23
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
24
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
25
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
27
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
28
|
};
|
|
28
29
|
run(): Promise<void>;
|
|
@@ -31,6 +32,13 @@ export default class AccessGroups extends Command {
|
|
|
31
32
|
private runCamt053Import;
|
|
32
33
|
private runNestedImport;
|
|
33
34
|
private parseFilterValue;
|
|
35
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
36
|
+
private printPageSummary;
|
|
37
|
+
/**
|
|
38
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
39
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
40
|
+
*/
|
|
41
|
+
private warnShortPage;
|
|
34
42
|
private sanitizeOutput;
|
|
35
43
|
private getColumns;
|
|
36
44
|
private getValue;
|
|
@@ -6,10 +6,11 @@ const HAS_IMPORT = true;
|
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["list", "create", "list-summaries", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/access-groups', summary: 'List access groups (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
12
|
'create': { method: 'POST', path: '/v1/access-groups', summary: 'Create a new access group', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
|
|
13
|
+
'list-summaries': { method: 'GET', path: '/v1/access-groups/summaries', summary: 'List access groups without members (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
14
|
'get': { method: 'GET', path: '/v1/access-groups/{id}', summary: 'Get a single access group by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
15
|
'update': { method: 'PATCH', path: '/v1/access-groups/{id}', summary: 'Update an existing access group', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
|
|
15
16
|
'delete': { method: 'DELETE', path: '/v1/access-groups/{id}', summary: 'Delete an access group', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
@@ -45,6 +46,7 @@ export default class AccessGroups extends Command {
|
|
|
45
46
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
46
47
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
47
48
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
49
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
48
50
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
51
|
};
|
|
50
52
|
async run() {
|
|
@@ -337,9 +339,15 @@ export default class AccessGroups extends Command {
|
|
|
337
339
|
}
|
|
338
340
|
catch { /* keep as string */ }
|
|
339
341
|
}
|
|
340
|
-
//
|
|
342
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
343
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
344
|
+
// dropping it silently let a script read one page as the whole result
|
|
345
|
+
// (AderisERP/product#61).
|
|
346
|
+
let envelope;
|
|
341
347
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
342
|
-
|
|
348
|
+
const page = output;
|
|
349
|
+
envelope = page;
|
|
350
|
+
output = page.data;
|
|
343
351
|
}
|
|
344
352
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
345
353
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -356,12 +364,24 @@ export default class AccessGroups extends Command {
|
|
|
356
364
|
output = this.sanitizeOutput(output);
|
|
357
365
|
}
|
|
358
366
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
359
|
-
if (
|
|
367
|
+
if (envelope)
|
|
368
|
+
this.warnShortPage(envelope, flags.limit);
|
|
369
|
+
if (flags.csv || flags.output === 'csv') {
|
|
360
370
|
this.printCsv(output, fieldList);
|
|
361
|
-
|
|
371
|
+
}
|
|
372
|
+
else if (flags.table || flags.output === 'table') {
|
|
362
373
|
this.printTable(output, fieldList);
|
|
363
|
-
|
|
374
|
+
if (envelope)
|
|
375
|
+
this.printPageSummary(envelope);
|
|
376
|
+
}
|
|
377
|
+
else if (envelope && flags.meta) {
|
|
378
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
379
|
+
// a bare array so existing scripts are unaffected.
|
|
380
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
364
383
|
this.log(JSON.stringify(output, null, 2));
|
|
384
|
+
}
|
|
365
385
|
}
|
|
366
386
|
catch (error) {
|
|
367
387
|
if (error instanceof ApiError) {
|
|
@@ -990,6 +1010,34 @@ export default class AccessGroups extends Command {
|
|
|
990
1010
|
return `\$${op}`;
|
|
991
1011
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
992
1012
|
}
|
|
1013
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1014
|
+
printPageSummary(envelope) {
|
|
1015
|
+
const meta = envelope.meta;
|
|
1016
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1017
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1018
|
+
this.log(`
|
|
1019
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1020
|
+
}
|
|
1021
|
+
for (const total of envelope.totals ?? []) {
|
|
1022
|
+
const { currency, ...sums } = total;
|
|
1023
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1024
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
/**
|
|
1028
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1029
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1030
|
+
*/
|
|
1031
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1032
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1033
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1034
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1035
|
+
return;
|
|
1036
|
+
const pages = envelope.meta?.totalPages;
|
|
1037
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1038
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1039
|
+
`);
|
|
1040
|
+
}
|
|
993
1041
|
sanitizeOutput(data) {
|
|
994
1042
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
995
1043
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -23,6 +23,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
23
23
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
24
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
25
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
27
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
28
|
};
|
|
28
29
|
run(): Promise<void>;
|
|
@@ -31,6 +32,13 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
31
32
|
private runCamt053Import;
|
|
32
33
|
private runNestedImport;
|
|
33
34
|
private parseFilterValue;
|
|
35
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
36
|
+
private printPageSummary;
|
|
37
|
+
/**
|
|
38
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
39
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
40
|
+
*/
|
|
41
|
+
private warnShortPage;
|
|
34
42
|
private sanitizeOutput;
|
|
35
43
|
private getColumns;
|
|
36
44
|
private getValue;
|
|
@@ -39,6 +39,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
39
39
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
40
40
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
41
41
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
42
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
42
43
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
43
44
|
};
|
|
44
45
|
async run() {
|
|
@@ -331,9 +332,15 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
331
332
|
}
|
|
332
333
|
catch { /* keep as string */ }
|
|
333
334
|
}
|
|
334
|
-
//
|
|
335
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
336
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
337
|
+
// dropping it silently let a script read one page as the whole result
|
|
338
|
+
// (AderisERP/product#61).
|
|
339
|
+
let envelope;
|
|
335
340
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
336
|
-
|
|
341
|
+
const page = output;
|
|
342
|
+
envelope = page;
|
|
343
|
+
output = page.data;
|
|
337
344
|
}
|
|
338
345
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
339
346
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -350,12 +357,24 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
350
357
|
output = this.sanitizeOutput(output);
|
|
351
358
|
}
|
|
352
359
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
353
|
-
if (
|
|
360
|
+
if (envelope)
|
|
361
|
+
this.warnShortPage(envelope, flags.limit);
|
|
362
|
+
if (flags.csv || flags.output === 'csv') {
|
|
354
363
|
this.printCsv(output, fieldList);
|
|
355
|
-
|
|
364
|
+
}
|
|
365
|
+
else if (flags.table || flags.output === 'table') {
|
|
356
366
|
this.printTable(output, fieldList);
|
|
357
|
-
|
|
367
|
+
if (envelope)
|
|
368
|
+
this.printPageSummary(envelope);
|
|
369
|
+
}
|
|
370
|
+
else if (envelope && flags.meta) {
|
|
371
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
372
|
+
// a bare array so existing scripts are unaffected.
|
|
373
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
358
376
|
this.log(JSON.stringify(output, null, 2));
|
|
377
|
+
}
|
|
359
378
|
}
|
|
360
379
|
catch (error) {
|
|
361
380
|
if (error instanceof ApiError) {
|
|
@@ -984,6 +1003,34 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
984
1003
|
return `\$${op}`;
|
|
985
1004
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
986
1005
|
}
|
|
1006
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1007
|
+
printPageSummary(envelope) {
|
|
1008
|
+
const meta = envelope.meta;
|
|
1009
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1010
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1011
|
+
this.log(`
|
|
1012
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1013
|
+
}
|
|
1014
|
+
for (const total of envelope.totals ?? []) {
|
|
1015
|
+
const { currency, ...sums } = total;
|
|
1016
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1017
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1022
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1023
|
+
*/
|
|
1024
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1025
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1026
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1027
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1028
|
+
return;
|
|
1029
|
+
const pages = envelope.meta?.totalPages;
|
|
1030
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1031
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1032
|
+
`);
|
|
1033
|
+
}
|
|
987
1034
|
sanitizeOutput(data) {
|
|
988
1035
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
989
1036
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -25,6 +25,7 @@ export default class AccountTransactions extends Command {
|
|
|
25
25
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
26
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
27
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
29
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
30
|
};
|
|
30
31
|
run(): Promise<void>;
|
|
@@ -33,6 +34,13 @@ export default class AccountTransactions extends Command {
|
|
|
33
34
|
private runCamt053Import;
|
|
34
35
|
private runNestedImport;
|
|
35
36
|
private parseFilterValue;
|
|
37
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
38
|
+
private printPageSummary;
|
|
39
|
+
/**
|
|
40
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
41
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
42
|
+
*/
|
|
43
|
+
private warnShortPage;
|
|
36
44
|
private sanitizeOutput;
|
|
37
45
|
private getColumns;
|
|
38
46
|
private getValue;
|
|
@@ -6,12 +6,13 @@ const HAS_IMPORT = true;
|
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = true;
|
|
8
8
|
const NESTED_IMPORTS = ["allocations", "allocations-notes", "notes"];
|
|
9
|
-
const SUBCOMMANDS = [...["retry-booking", "recover-booking", "list", "create", "get", "update", "delete", "reconcile", "allocations-reprocess-unbooked", "allocations-unbooked", "list-allocations", "create-allocations", "get-allocations", "update-allocations", "delete-allocations", "list-allocations-settlement-accounts", "allocations-confirm", "import", "import-camt053", "list-allocations-notes", "create-allocations-notes", "get-allocations-notes", "update-allocations-notes", "delete-allocations-notes", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["retry-booking", "recover-booking", "list", "create", "status-counts", "get", "update", "delete", "reconcile", "allocations-reprocess-unbooked", "allocations-unbooked", "list-allocations", "create-allocations", "get-allocations", "update-allocations", "delete-allocations", "list-allocations-settlement-accounts", "allocations-confirm", "import", "import-camt053", "list-allocations-notes", "create-allocations-notes", "get-allocations-notes", "update-allocations-notes", "delete-allocations-notes", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'retry-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/retry-booking', summary: 'Retry complete booking of an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
12
12
|
'recover-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/recover-booking', summary: 'Verify existing accounting and book missing entries together', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
13
13
|
'list': { method: 'GET', path: '/v1/account-transactions', summary: 'Get all account transactions with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
14
14
|
'create': { method: 'POST', path: '/v1/account-transactions', summary: 'Create a new account transaction', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
15
|
+
'status-counts': { method: 'GET', path: '/v1/account-transactions/status-counts', summary: 'Count account transactions per reconciliation status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
16
|
'get': { method: 'GET', path: '/v1/account-transactions/{id}', summary: 'Get an account transaction by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
17
|
'update': { method: 'PATCH', path: '/v1/account-transactions/{id}', summary: 'Update an account transaction', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
17
18
|
'delete': { method: 'DELETE', path: '/v1/account-transactions/{id}', summary: 'Delete an account transaction', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
@@ -25,7 +26,7 @@ const ENDPOINTS = {
|
|
|
25
26
|
'delete-allocations': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Delete an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
27
|
'list-allocations-settlement-accounts': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/settlement-accounts', summary: 'Which account each ledger would settle the allocated document against', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
28
|
'allocations-confirm': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/confirm', summary: 'Confirm an allocation (transition from REVIEW to CONFIRMED)', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['counterAccounts'] },
|
|
28
|
-
'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import
|
|
29
|
+
'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import account transactions', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
30
|
'import-camt053': { method: 'POST', path: '/v1/account-transactions/import/camt053', summary: 'Import CAMT.053 bank statement (ISO 20022 format)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
31
|
'list-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Get all notes for an allocation', pathParams: ['allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
32
|
'create-allocations-notes': { method: 'POST', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Create a note for an allocation', pathParams: ['allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
@@ -71,6 +72,7 @@ export default class AccountTransactions extends Command {
|
|
|
71
72
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
72
73
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
73
74
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
75
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
74
76
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
75
77
|
};
|
|
76
78
|
async run() {
|
|
@@ -363,9 +365,15 @@ export default class AccountTransactions extends Command {
|
|
|
363
365
|
}
|
|
364
366
|
catch { /* keep as string */ }
|
|
365
367
|
}
|
|
366
|
-
//
|
|
368
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
369
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
370
|
+
// dropping it silently let a script read one page as the whole result
|
|
371
|
+
// (AderisERP/product#61).
|
|
372
|
+
let envelope;
|
|
367
373
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
368
|
-
|
|
374
|
+
const page = output;
|
|
375
|
+
envelope = page;
|
|
376
|
+
output = page.data;
|
|
369
377
|
}
|
|
370
378
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
371
379
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -382,12 +390,24 @@ export default class AccountTransactions extends Command {
|
|
|
382
390
|
output = this.sanitizeOutput(output);
|
|
383
391
|
}
|
|
384
392
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
385
|
-
if (
|
|
393
|
+
if (envelope)
|
|
394
|
+
this.warnShortPage(envelope, flags.limit);
|
|
395
|
+
if (flags.csv || flags.output === 'csv') {
|
|
386
396
|
this.printCsv(output, fieldList);
|
|
387
|
-
|
|
397
|
+
}
|
|
398
|
+
else if (flags.table || flags.output === 'table') {
|
|
388
399
|
this.printTable(output, fieldList);
|
|
389
|
-
|
|
400
|
+
if (envelope)
|
|
401
|
+
this.printPageSummary(envelope);
|
|
402
|
+
}
|
|
403
|
+
else if (envelope && flags.meta) {
|
|
404
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
405
|
+
// a bare array so existing scripts are unaffected.
|
|
406
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
390
409
|
this.log(JSON.stringify(output, null, 2));
|
|
410
|
+
}
|
|
391
411
|
}
|
|
392
412
|
catch (error) {
|
|
393
413
|
if (error instanceof ApiError) {
|
|
@@ -1016,6 +1036,34 @@ export default class AccountTransactions extends Command {
|
|
|
1016
1036
|
return `\$${op}`;
|
|
1017
1037
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
1018
1038
|
}
|
|
1039
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1040
|
+
printPageSummary(envelope) {
|
|
1041
|
+
const meta = envelope.meta;
|
|
1042
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1043
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1044
|
+
this.log(`
|
|
1045
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1046
|
+
}
|
|
1047
|
+
for (const total of envelope.totals ?? []) {
|
|
1048
|
+
const { currency, ...sums } = total;
|
|
1049
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1050
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1055
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1056
|
+
*/
|
|
1057
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1058
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1059
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1060
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1061
|
+
return;
|
|
1062
|
+
const pages = envelope.meta?.totalPages;
|
|
1063
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1064
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1065
|
+
`);
|
|
1066
|
+
}
|
|
1019
1067
|
sanitizeOutput(data) {
|
|
1020
1068
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1021
1069
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -24,6 +24,7 @@ export default class Accounts extends Command {
|
|
|
24
24
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
25
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
26
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
28
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
29
|
};
|
|
29
30
|
run(): Promise<void>;
|
|
@@ -32,6 +33,13 @@ export default class Accounts extends Command {
|
|
|
32
33
|
private runCamt053Import;
|
|
33
34
|
private runNestedImport;
|
|
34
35
|
private parseFilterValue;
|
|
36
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
37
|
+
private printPageSummary;
|
|
38
|
+
/**
|
|
39
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
40
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
41
|
+
*/
|
|
42
|
+
private warnShortPage;
|
|
35
43
|
private sanitizeOutput;
|
|
36
44
|
private getColumns;
|
|
37
45
|
private getValue;
|
|
@@ -51,6 +51,7 @@ export default class Accounts extends Command {
|
|
|
51
51
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
52
52
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
53
53
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
54
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
54
55
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
55
56
|
};
|
|
56
57
|
async run() {
|
|
@@ -343,9 +344,15 @@ export default class Accounts extends Command {
|
|
|
343
344
|
}
|
|
344
345
|
catch { /* keep as string */ }
|
|
345
346
|
}
|
|
346
|
-
//
|
|
347
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
348
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
349
|
+
// dropping it silently let a script read one page as the whole result
|
|
350
|
+
// (AderisERP/product#61).
|
|
351
|
+
let envelope;
|
|
347
352
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
348
|
-
|
|
353
|
+
const page = output;
|
|
354
|
+
envelope = page;
|
|
355
|
+
output = page.data;
|
|
349
356
|
}
|
|
350
357
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
351
358
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -362,12 +369,24 @@ export default class Accounts extends Command {
|
|
|
362
369
|
output = this.sanitizeOutput(output);
|
|
363
370
|
}
|
|
364
371
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
365
|
-
if (
|
|
372
|
+
if (envelope)
|
|
373
|
+
this.warnShortPage(envelope, flags.limit);
|
|
374
|
+
if (flags.csv || flags.output === 'csv') {
|
|
366
375
|
this.printCsv(output, fieldList);
|
|
367
|
-
|
|
376
|
+
}
|
|
377
|
+
else if (flags.table || flags.output === 'table') {
|
|
368
378
|
this.printTable(output, fieldList);
|
|
369
|
-
|
|
379
|
+
if (envelope)
|
|
380
|
+
this.printPageSummary(envelope);
|
|
381
|
+
}
|
|
382
|
+
else if (envelope && flags.meta) {
|
|
383
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
384
|
+
// a bare array so existing scripts are unaffected.
|
|
385
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
370
388
|
this.log(JSON.stringify(output, null, 2));
|
|
389
|
+
}
|
|
371
390
|
}
|
|
372
391
|
catch (error) {
|
|
373
392
|
if (error instanceof ApiError) {
|
|
@@ -996,6 +1015,34 @@ export default class Accounts extends Command {
|
|
|
996
1015
|
return `\$${op}`;
|
|
997
1016
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
998
1017
|
}
|
|
1018
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1019
|
+
printPageSummary(envelope) {
|
|
1020
|
+
const meta = envelope.meta;
|
|
1021
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1022
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1023
|
+
this.log(`
|
|
1024
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1025
|
+
}
|
|
1026
|
+
for (const total of envelope.totals ?? []) {
|
|
1027
|
+
const { currency, ...sums } = total;
|
|
1028
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1029
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1034
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1035
|
+
*/
|
|
1036
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1037
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1038
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1039
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1040
|
+
return;
|
|
1041
|
+
const pages = envelope.meta?.totalPages;
|
|
1042
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1043
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1044
|
+
`);
|
|
1045
|
+
}
|
|
999
1046
|
sanitizeOutput(data) {
|
|
1000
1047
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1001
1048
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -24,6 +24,7 @@ export default class AgentPlatform extends Command {
|
|
|
24
24
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
25
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
26
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
28
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
29
|
};
|
|
29
30
|
run(): Promise<void>;
|
|
@@ -32,6 +33,13 @@ export default class AgentPlatform extends Command {
|
|
|
32
33
|
private runCamt053Import;
|
|
33
34
|
private runNestedImport;
|
|
34
35
|
private parseFilterValue;
|
|
36
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
37
|
+
private printPageSummary;
|
|
38
|
+
/**
|
|
39
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
40
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
41
|
+
*/
|
|
42
|
+
private warnShortPage;
|
|
35
43
|
private sanitizeOutput;
|
|
36
44
|
private getColumns;
|
|
37
45
|
private getValue;
|
|
@@ -43,6 +43,7 @@ export default class AgentPlatform extends Command {
|
|
|
43
43
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
44
44
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
45
45
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
46
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
46
47
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
47
48
|
};
|
|
48
49
|
async run() {
|
|
@@ -335,9 +336,15 @@ export default class AgentPlatform extends Command {
|
|
|
335
336
|
}
|
|
336
337
|
catch { /* keep as string */ }
|
|
337
338
|
}
|
|
338
|
-
//
|
|
339
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
340
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
341
|
+
// dropping it silently let a script read one page as the whole result
|
|
342
|
+
// (AderisERP/product#61).
|
|
343
|
+
let envelope;
|
|
339
344
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
340
|
-
|
|
345
|
+
const page = output;
|
|
346
|
+
envelope = page;
|
|
347
|
+
output = page.data;
|
|
341
348
|
}
|
|
342
349
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
343
350
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -354,12 +361,24 @@ export default class AgentPlatform extends Command {
|
|
|
354
361
|
output = this.sanitizeOutput(output);
|
|
355
362
|
}
|
|
356
363
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
357
|
-
if (
|
|
364
|
+
if (envelope)
|
|
365
|
+
this.warnShortPage(envelope, flags.limit);
|
|
366
|
+
if (flags.csv || flags.output === 'csv') {
|
|
358
367
|
this.printCsv(output, fieldList);
|
|
359
|
-
|
|
368
|
+
}
|
|
369
|
+
else if (flags.table || flags.output === 'table') {
|
|
360
370
|
this.printTable(output, fieldList);
|
|
361
|
-
|
|
371
|
+
if (envelope)
|
|
372
|
+
this.printPageSummary(envelope);
|
|
373
|
+
}
|
|
374
|
+
else if (envelope && flags.meta) {
|
|
375
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
376
|
+
// a bare array so existing scripts are unaffected.
|
|
377
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
362
380
|
this.log(JSON.stringify(output, null, 2));
|
|
381
|
+
}
|
|
363
382
|
}
|
|
364
383
|
catch (error) {
|
|
365
384
|
if (error instanceof ApiError) {
|
|
@@ -988,6 +1007,34 @@ export default class AgentPlatform extends Command {
|
|
|
988
1007
|
return `\$${op}`;
|
|
989
1008
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
990
1009
|
}
|
|
1010
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1011
|
+
printPageSummary(envelope) {
|
|
1012
|
+
const meta = envelope.meta;
|
|
1013
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1014
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1015
|
+
this.log(`
|
|
1016
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1017
|
+
}
|
|
1018
|
+
for (const total of envelope.totals ?? []) {
|
|
1019
|
+
const { currency, ...sums } = total;
|
|
1020
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1021
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1026
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1027
|
+
*/
|
|
1028
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1029
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1030
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1031
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1032
|
+
return;
|
|
1033
|
+
const pages = envelope.meta?.totalPages;
|
|
1034
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1035
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1036
|
+
`);
|
|
1037
|
+
}
|
|
991
1038
|
sanitizeOutput(data) {
|
|
992
1039
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
993
1040
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -23,6 +23,7 @@ export default class AgentRuns extends Command {
|
|
|
23
23
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
24
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
25
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
27
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
28
|
};
|
|
28
29
|
run(): Promise<void>;
|
|
@@ -31,6 +32,13 @@ export default class AgentRuns extends Command {
|
|
|
31
32
|
private runCamt053Import;
|
|
32
33
|
private runNestedImport;
|
|
33
34
|
private parseFilterValue;
|
|
35
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
36
|
+
private printPageSummary;
|
|
37
|
+
/**
|
|
38
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
39
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
40
|
+
*/
|
|
41
|
+
private warnShortPage;
|
|
34
42
|
private sanitizeOutput;
|
|
35
43
|
private getColumns;
|
|
36
44
|
private getValue;
|