@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
|
@@ -45,6 +45,7 @@ export default class SalaryTypes extends Command {
|
|
|
45
45
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
46
46
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
47
47
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
48
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
48
49
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
50
|
};
|
|
50
51
|
async run() {
|
|
@@ -337,9 +338,15 @@ export default class SalaryTypes extends Command {
|
|
|
337
338
|
}
|
|
338
339
|
catch { /* keep as string */ }
|
|
339
340
|
}
|
|
340
|
-
//
|
|
341
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
342
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
343
|
+
// dropping it silently let a script read one page as the whole result
|
|
344
|
+
// (AderisERP/product#61).
|
|
345
|
+
let envelope;
|
|
341
346
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
342
|
-
|
|
347
|
+
const page = output;
|
|
348
|
+
envelope = page;
|
|
349
|
+
output = page.data;
|
|
343
350
|
}
|
|
344
351
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
345
352
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -356,12 +363,24 @@ export default class SalaryTypes extends Command {
|
|
|
356
363
|
output = this.sanitizeOutput(output);
|
|
357
364
|
}
|
|
358
365
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
359
|
-
if (
|
|
366
|
+
if (envelope)
|
|
367
|
+
this.warnShortPage(envelope, flags.limit);
|
|
368
|
+
if (flags.csv || flags.output === 'csv') {
|
|
360
369
|
this.printCsv(output, fieldList);
|
|
361
|
-
|
|
370
|
+
}
|
|
371
|
+
else if (flags.table || flags.output === 'table') {
|
|
362
372
|
this.printTable(output, fieldList);
|
|
363
|
-
|
|
373
|
+
if (envelope)
|
|
374
|
+
this.printPageSummary(envelope);
|
|
375
|
+
}
|
|
376
|
+
else if (envelope && flags.meta) {
|
|
377
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
378
|
+
// a bare array so existing scripts are unaffected.
|
|
379
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
364
382
|
this.log(JSON.stringify(output, null, 2));
|
|
383
|
+
}
|
|
365
384
|
}
|
|
366
385
|
catch (error) {
|
|
367
386
|
if (error instanceof ApiError) {
|
|
@@ -990,6 +1009,34 @@ export default class SalaryTypes extends Command {
|
|
|
990
1009
|
return `\$${op}`;
|
|
991
1010
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
992
1011
|
}
|
|
1012
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1013
|
+
printPageSummary(envelope) {
|
|
1014
|
+
const meta = envelope.meta;
|
|
1015
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1016
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1017
|
+
this.log(`
|
|
1018
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1019
|
+
}
|
|
1020
|
+
for (const total of envelope.totals ?? []) {
|
|
1021
|
+
const { currency, ...sums } = total;
|
|
1022
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1023
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1028
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1029
|
+
*/
|
|
1030
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1031
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1032
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1033
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1034
|
+
return;
|
|
1035
|
+
const pages = envelope.meta?.totalPages;
|
|
1036
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1037
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1038
|
+
`);
|
|
1039
|
+
}
|
|
993
1040
|
sanitizeOutput(data) {
|
|
994
1041
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
995
1042
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -14,9 +14,11 @@ export default class SalesInvoices extends Command {
|
|
|
14
14
|
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
15
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
16
|
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'offset-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
18
|
'line-item-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
19
|
'note-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
20
|
'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'payment-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
22
|
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
23
|
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
24
|
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -26,6 +28,7 @@ export default class SalesInvoices extends Command {
|
|
|
26
28
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
29
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
30
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
31
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
32
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
30
33
|
};
|
|
31
34
|
run(): Promise<void>;
|
|
@@ -34,6 +37,13 @@ export default class SalesInvoices extends Command {
|
|
|
34
37
|
private runCamt053Import;
|
|
35
38
|
private runNestedImport;
|
|
36
39
|
private parseFilterValue;
|
|
40
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
41
|
+
private printPageSummary;
|
|
42
|
+
/**
|
|
43
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
44
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
45
|
+
*/
|
|
46
|
+
private warnShortPage;
|
|
37
47
|
private sanitizeOutput;
|
|
38
48
|
private getColumns;
|
|
39
49
|
private getValue;
|
|
@@ -6,8 +6,11 @@ const HAS_IMPORT = true;
|
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = ["migrated-invoice", "line-items", "notes", "files"];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "create-migrated-invoice", "get-pdf", "create-pdf", "get", "update", "delete", "payment-derivation", "update-migrated-invoice", "approve", "match", "validate", "request-approval", "send", "send-resend", "cancel", "copy", "replace", "rebuild-journal", "recalculate-payment-status", "merge", "create-line-items", "line-items-from-sales-order", "line-items-from-delivery-note", "update-line-items-reorder", "update-line-items", "delete-line-items", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
9
|
+
const SUBCOMMANDS = [...["create-offsets", "delete-offsets", "offset-candidates", "list", "create", "create-migrated-invoice", "get-pdf", "create-pdf", "get", "update", "delete", "payment-derivation", "update-migrated-invoice", "approve", "match", "validate", "request-approval", "send", "send-resend", "cancel", "copy", "replace", "rebuild-journal", "recalculate-payment-status", "merge", "create-line-items", "line-items-from-sales-order", "line-items-from-delivery-note", "update-line-items-reorder", "update-line-items", "delete-line-items", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "line-items-from-sales-invoice", "credit-notes", "list-refund-account-options", "update-refund-payments-beneficiary-account"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
+
'create-offsets': { method: 'POST', path: '/v1/sales-invoices/{salesInvoiceId}/offsets', summary: 'Deduct a prepayment or credit note from a sales invoice', pathParams: ['salesInvoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
|
+
'delete-offsets': { method: 'DELETE', path: '/v1/sales-invoices/{salesInvoiceId}/offsets/{offsetId}', summary: 'Remove a deduction of a prepayment or credit note from a sales invoice', pathParams: ['salesInvoiceId', 'offsetId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
13
|
+
'offset-candidates': { method: 'GET', path: '/v1/sales-invoices/{salesInvoiceId}/offset-candidates', summary: 'List the prepayments and credit notes that can be deducted from a sales invoice', pathParams: ['salesInvoiceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
11
14
|
'list': { method: 'GET', path: '/v1/sales-invoices', summary: 'Get all sales invoices with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
12
15
|
'create': { method: 'POST', path: '/v1/sales-invoices', summary: 'Create a new sales invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['earlyPaymentDiscounts', 'lineItems', 'discounts', 'files', 'notes', 'totalAmountByTaxRate', 'tagIds', 'tagCodes', 'invoiceEmailCc'] },
|
|
13
16
|
'create-migrated-invoice': { method: 'POST', path: '/v1/sales-invoices/create-migrated-invoice', summary: 'Create a sales invoice with explicit tax codes on line items (for data migration)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lineItems', 'files', 'notes', 'totalAmountByTaxRate', 'tagIds', 'tagCodes', 'invoiceEmailCc'] },
|
|
@@ -47,6 +50,10 @@ const ENDPOINTS = {
|
|
|
47
50
|
'update-files': { method: 'PATCH', path: '/v1/sales-invoices/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a sales invoice', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
48
51
|
'delete-files': { method: 'DELETE', path: '/v1/sales-invoices/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a sales invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
49
52
|
'files-download': { method: 'GET', path: '/v1/sales-invoices/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a sales invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
53
|
+
'line-items-from-sales-invoice': { method: 'POST', path: '/v1/sales-invoices/{invoiceId}/line-items/from-sales-invoice', summary: 'Add line items to a sales credit note from a sales invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'] },
|
|
54
|
+
'credit-notes': { method: 'POST', path: '/v1/sales-invoices/{invoiceId}/credit-notes', summary: 'Create a sales credit note from a sales invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'] },
|
|
55
|
+
'list-refund-account-options': { method: 'GET', path: '/v1/sales-invoices/{salesInvoiceId}/refund-account-options', summary: 'List the accounts the refund of a sales credit note can be paid to', pathParams: ['salesInvoiceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
56
|
+
'update-refund-payments-beneficiary-account': { method: 'PUT', path: '/v1/sales-invoices/{salesInvoiceId}/refund-payments/{paymentId}/beneficiary-account', summary: 'Choose the account a refund payment pays to', pathParams: ['salesInvoiceId', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
50
57
|
};
|
|
51
58
|
export default class SalesInvoices extends Command {
|
|
52
59
|
static description = 'Manage sales invoices';
|
|
@@ -70,9 +77,11 @@ export default class SalesInvoices extends Command {
|
|
|
70
77
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
71
78
|
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
72
79
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
80
|
+
'offset-id': Flags.string({ description: 'Path param: offsetId' }),
|
|
73
81
|
'line-item-id': Flags.string({ description: 'Path param: lineItemId' }),
|
|
74
82
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
75
83
|
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
84
|
+
'payment-id': Flags.string({ description: 'Path param: paymentId' }),
|
|
76
85
|
page: Flags.string({ description: 'Page number' }),
|
|
77
86
|
limit: Flags.string({ description: 'Items per page' }),
|
|
78
87
|
include: Flags.string({ description: 'Relations to include' }),
|
|
@@ -82,6 +91,7 @@ export default class SalesInvoices extends Command {
|
|
|
82
91
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
83
92
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
84
93
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
94
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
85
95
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
86
96
|
};
|
|
87
97
|
async run() {
|
|
@@ -374,9 +384,15 @@ export default class SalesInvoices extends Command {
|
|
|
374
384
|
}
|
|
375
385
|
catch { /* keep as string */ }
|
|
376
386
|
}
|
|
377
|
-
//
|
|
387
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
388
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
389
|
+
// dropping it silently let a script read one page as the whole result
|
|
390
|
+
// (AderisERP/product#61).
|
|
391
|
+
let envelope;
|
|
378
392
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
379
|
-
|
|
393
|
+
const page = output;
|
|
394
|
+
envelope = page;
|
|
395
|
+
output = page.data;
|
|
380
396
|
}
|
|
381
397
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
382
398
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -393,12 +409,24 @@ export default class SalesInvoices extends Command {
|
|
|
393
409
|
output = this.sanitizeOutput(output);
|
|
394
410
|
}
|
|
395
411
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
396
|
-
if (
|
|
412
|
+
if (envelope)
|
|
413
|
+
this.warnShortPage(envelope, flags.limit);
|
|
414
|
+
if (flags.csv || flags.output === 'csv') {
|
|
397
415
|
this.printCsv(output, fieldList);
|
|
398
|
-
|
|
416
|
+
}
|
|
417
|
+
else if (flags.table || flags.output === 'table') {
|
|
399
418
|
this.printTable(output, fieldList);
|
|
400
|
-
|
|
419
|
+
if (envelope)
|
|
420
|
+
this.printPageSummary(envelope);
|
|
421
|
+
}
|
|
422
|
+
else if (envelope && flags.meta) {
|
|
423
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
424
|
+
// a bare array so existing scripts are unaffected.
|
|
425
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
401
428
|
this.log(JSON.stringify(output, null, 2));
|
|
429
|
+
}
|
|
402
430
|
}
|
|
403
431
|
catch (error) {
|
|
404
432
|
if (error instanceof ApiError) {
|
|
@@ -1027,6 +1055,34 @@ export default class SalesInvoices extends Command {
|
|
|
1027
1055
|
return `\$${op}`;
|
|
1028
1056
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
1029
1057
|
}
|
|
1058
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1059
|
+
printPageSummary(envelope) {
|
|
1060
|
+
const meta = envelope.meta;
|
|
1061
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1062
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1063
|
+
this.log(`
|
|
1064
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1065
|
+
}
|
|
1066
|
+
for (const total of envelope.totals ?? []) {
|
|
1067
|
+
const { currency, ...sums } = total;
|
|
1068
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1069
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1074
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1075
|
+
*/
|
|
1076
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1077
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1078
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1079
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1080
|
+
return;
|
|
1081
|
+
const pages = envelope.meta?.totalPages;
|
|
1082
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1083
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1084
|
+
`);
|
|
1085
|
+
}
|
|
1030
1086
|
sanitizeOutput(data) {
|
|
1031
1087
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1032
1088
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -26,6 +26,7 @@ export default class SalesOrders extends Command {
|
|
|
26
26
|
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
27
|
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
28
|
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
30
|
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
30
31
|
};
|
|
31
32
|
run(): Promise<void>;
|
|
@@ -34,6 +35,13 @@ export default class SalesOrders extends Command {
|
|
|
34
35
|
private runCamt053Import;
|
|
35
36
|
private runNestedImport;
|
|
36
37
|
private parseFilterValue;
|
|
38
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
39
|
+
private printPageSummary;
|
|
40
|
+
/**
|
|
41
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
42
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
43
|
+
*/
|
|
44
|
+
private warnShortPage;
|
|
37
45
|
private sanitizeOutput;
|
|
38
46
|
private getColumns;
|
|
39
47
|
private getValue;
|
|
@@ -76,6 +76,7 @@ export default class SalesOrders extends Command {
|
|
|
76
76
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
77
77
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
78
78
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
79
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
79
80
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
80
81
|
};
|
|
81
82
|
async run() {
|
|
@@ -368,9 +369,15 @@ export default class SalesOrders extends Command {
|
|
|
368
369
|
}
|
|
369
370
|
catch { /* keep as string */ }
|
|
370
371
|
}
|
|
371
|
-
//
|
|
372
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
373
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
374
|
+
// dropping it silently let a script read one page as the whole result
|
|
375
|
+
// (AderisERP/product#61).
|
|
376
|
+
let envelope;
|
|
372
377
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
373
|
-
|
|
378
|
+
const page = output;
|
|
379
|
+
envelope = page;
|
|
380
|
+
output = page.data;
|
|
374
381
|
}
|
|
375
382
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
376
383
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -387,12 +394,24 @@ export default class SalesOrders extends Command {
|
|
|
387
394
|
output = this.sanitizeOutput(output);
|
|
388
395
|
}
|
|
389
396
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
390
|
-
if (
|
|
397
|
+
if (envelope)
|
|
398
|
+
this.warnShortPage(envelope, flags.limit);
|
|
399
|
+
if (flags.csv || flags.output === 'csv') {
|
|
391
400
|
this.printCsv(output, fieldList);
|
|
392
|
-
|
|
401
|
+
}
|
|
402
|
+
else if (flags.table || flags.output === 'table') {
|
|
393
403
|
this.printTable(output, fieldList);
|
|
394
|
-
|
|
404
|
+
if (envelope)
|
|
405
|
+
this.printPageSummary(envelope);
|
|
406
|
+
}
|
|
407
|
+
else if (envelope && flags.meta) {
|
|
408
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
409
|
+
// a bare array so existing scripts are unaffected.
|
|
410
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
395
413
|
this.log(JSON.stringify(output, null, 2));
|
|
414
|
+
}
|
|
396
415
|
}
|
|
397
416
|
catch (error) {
|
|
398
417
|
if (error instanceof ApiError) {
|
|
@@ -1021,6 +1040,34 @@ export default class SalesOrders extends Command {
|
|
|
1021
1040
|
return `\$${op}`;
|
|
1022
1041
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
1023
1042
|
}
|
|
1043
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1044
|
+
printPageSummary(envelope) {
|
|
1045
|
+
const meta = envelope.meta;
|
|
1046
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1047
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1048
|
+
this.log(`
|
|
1049
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1050
|
+
}
|
|
1051
|
+
for (const total of envelope.totals ?? []) {
|
|
1052
|
+
const { currency, ...sums } = total;
|
|
1053
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1054
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1059
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1060
|
+
*/
|
|
1061
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1062
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1063
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1064
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1065
|
+
return;
|
|
1066
|
+
const pages = envelope.meta?.totalPages;
|
|
1067
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1068
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1069
|
+
`);
|
|
1070
|
+
}
|
|
1024
1071
|
sanitizeOutput(data) {
|
|
1025
1072
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1026
1073
|
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 SavedViews 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 SavedViews 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 SavedViews 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 SavedViews 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 SavedViews 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 SavedViews 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;
|
|
@@ -23,6 +23,7 @@ export default class ScheduledProcessorMappings 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 ScheduledProcessorMappings 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;
|
|
@@ -45,6 +45,7 @@ export default class ScheduledProcessorMappings extends Command {
|
|
|
45
45
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
46
46
|
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
47
47
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
48
|
+
meta: Flags.boolean({ description: 'Keep the API envelope in JSON output: data plus page, totals and sums' }),
|
|
48
49
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
50
|
};
|
|
50
51
|
async run() {
|
|
@@ -337,9 +338,15 @@ export default class ScheduledProcessorMappings extends Command {
|
|
|
337
338
|
}
|
|
338
339
|
catch { /* keep as string */ }
|
|
339
340
|
}
|
|
340
|
-
//
|
|
341
|
+
// A paginated answer is { data, meta, links, totals }. The records are
|
|
342
|
+
// unwrapped for output, but what the API said about the page is kept:
|
|
343
|
+
// dropping it silently let a script read one page as the whole result
|
|
344
|
+
// (AderisERP/product#61).
|
|
345
|
+
let envelope;
|
|
341
346
|
if (output && typeof output === 'object' && !Array.isArray(output) && 'data' in output && Array.isArray(output.data)) {
|
|
342
|
-
|
|
347
|
+
const page = output;
|
|
348
|
+
envelope = page;
|
|
349
|
+
output = page.data;
|
|
343
350
|
}
|
|
344
351
|
// For table/csv on non-array responses, auto-extract the primary array
|
|
345
352
|
// e.g., { payments: [...], total: 3 } → extract payments array
|
|
@@ -356,12 +363,24 @@ export default class ScheduledProcessorMappings extends Command {
|
|
|
356
363
|
output = this.sanitizeOutput(output);
|
|
357
364
|
}
|
|
358
365
|
const fieldList = flags.fields?.split(',').map(f => f.trim());
|
|
359
|
-
if (
|
|
366
|
+
if (envelope)
|
|
367
|
+
this.warnShortPage(envelope, flags.limit);
|
|
368
|
+
if (flags.csv || flags.output === 'csv') {
|
|
360
369
|
this.printCsv(output, fieldList);
|
|
361
|
-
|
|
370
|
+
}
|
|
371
|
+
else if (flags.table || flags.output === 'table') {
|
|
362
372
|
this.printTable(output, fieldList);
|
|
363
|
-
|
|
373
|
+
if (envelope)
|
|
374
|
+
this.printPageSummary(envelope);
|
|
375
|
+
}
|
|
376
|
+
else if (envelope && flags.meta) {
|
|
377
|
+
// The whole envelope, for a caller that asked for it; the default stays
|
|
378
|
+
// a bare array so existing scripts are unaffected.
|
|
379
|
+
this.log(JSON.stringify({ ...envelope, data: output }, null, 2));
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
364
382
|
this.log(JSON.stringify(output, null, 2));
|
|
383
|
+
}
|
|
365
384
|
}
|
|
366
385
|
catch (error) {
|
|
367
386
|
if (error instanceof ApiError) {
|
|
@@ -990,6 +1009,34 @@ export default class ScheduledProcessorMappings extends Command {
|
|
|
990
1009
|
return `\$${op}`;
|
|
991
1010
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
992
1011
|
}
|
|
1012
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
1013
|
+
printPageSummary(envelope) {
|
|
1014
|
+
const meta = envelope.meta;
|
|
1015
|
+
if (meta && typeof meta.currentPage === 'number' && typeof meta.totalPages === 'number') {
|
|
1016
|
+
const shown = Array.isArray(envelope.data) ? envelope.data.length : 0;
|
|
1017
|
+
this.log(`
|
|
1018
|
+
Page ${meta.currentPage}/${meta.totalPages} — ${shown} of ${meta.totalItems ?? '?'} records`);
|
|
1019
|
+
}
|
|
1020
|
+
for (const total of envelope.totals ?? []) {
|
|
1021
|
+
const { currency, ...sums } = total;
|
|
1022
|
+
const parts = Object.entries(sums).map(([column, value]) => `${column} ${value}`).join(', ');
|
|
1023
|
+
this.log(`Total ${currency ?? ''}: ${parts}`.trim());
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
1028
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
1029
|
+
*/
|
|
1030
|
+
warnShortPage(envelope, requestedLimit) {
|
|
1031
|
+
const asked = requestedLimit === undefined ? undefined : Number(requestedLimit);
|
|
1032
|
+
const perPage = envelope.meta?.itemsPerPage;
|
|
1033
|
+
if (asked === undefined || Number.isNaN(asked) || typeof perPage !== 'number' || perPage >= asked)
|
|
1034
|
+
return;
|
|
1035
|
+
const pages = envelope.meta?.totalPages;
|
|
1036
|
+
const more = typeof pages === 'number' && pages > 1 ? ` Use --page, or the export action for every page.` : '';
|
|
1037
|
+
process.stderr.write(`! Asked for ${asked} records per page; the API returned at most ${perPage}.${more}
|
|
1038
|
+
`);
|
|
1039
|
+
}
|
|
993
1040
|
sanitizeOutput(data) {
|
|
994
1041
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
995
1042
|
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 Schedules 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 Schedules 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;
|