@aderis-erp/cli 1.0.14 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -8
- package/dist/commands/access-groups.d.ts +0 -1
- package/dist/commands/access-groups.js +22 -78
- package/dist/commands/account-transaction-allocations.d.ts +0 -1
- package/dist/commands/account-transaction-allocations.js +22 -78
- package/dist/commands/account-transactions.d.ts +0 -1
- package/dist/commands/account-transactions.js +28 -82
- package/dist/commands/accounts.d.ts +0 -1
- package/dist/commands/accounts.js +24 -80
- package/dist/commands/agent-platform.d.ts +0 -1
- package/dist/commands/agent-platform.js +24 -79
- package/dist/commands/analytics.d.ts +39 -0
- package/dist/commands/analytics.js +1113 -0
- package/dist/commands/{documents.d.ts → api-keys.d.ts} +1 -2
- package/dist/commands/api-keys.js +1117 -0
- package/dist/commands/audit-log.d.ts +0 -1
- package/dist/commands/audit-log.js +22 -78
- package/dist/commands/auth/login.d.ts +9 -0
- package/dist/commands/auth/login.js +83 -21
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.js +23 -6
- package/dist/commands/auth/status.js +46 -23
- package/dist/commands/auth/tenant.js +15 -9
- package/dist/commands/auth.d.ts +0 -1
- package/dist/commands/auth.js +37 -51
- package/dist/commands/bank-accounts.d.ts +0 -1
- package/dist/commands/bank-accounts.js +22 -78
- package/dist/commands/bank-integrations.d.ts +0 -1
- package/dist/commands/bank-integrations.js +22 -78
- package/dist/commands/business-partners.d.ts +1 -1
- package/dist/commands/business-partners.js +38 -84
- package/dist/commands/chat.d.ts +0 -1
- package/dist/commands/chat.js +22 -78
- package/dist/commands/config/add.d.ts +12 -0
- package/dist/commands/config/add.js +97 -17
- package/dist/commands/config/current.js +12 -4
- package/dist/commands/config/list.js +12 -4
- package/dist/commands/config/set-api-key.d.ts +10 -0
- package/dist/commands/config/set-api-key.js +49 -0
- package/dist/commands/config/use.js +3 -4
- package/dist/commands/credit-card-accounts.d.ts +0 -1
- package/dist/commands/credit-card-accounts.js +22 -78
- package/dist/commands/delivery-notes.d.ts +0 -1
- package/dist/commands/delivery-notes.js +29 -84
- package/dist/commands/dunning-configs.d.ts +0 -1
- package/dist/commands/dunning-configs.js +22 -78
- package/dist/commands/dunning-reminders.d.ts +0 -1
- package/dist/commands/dunning-reminders.js +22 -78
- package/dist/commands/dunning-runs.d.ts +0 -1
- package/dist/commands/dunning-runs.js +22 -78
- package/dist/commands/email-transactions.d.ts +0 -1
- package/dist/commands/email-transactions.js +22 -78
- package/dist/commands/employees.d.ts +0 -1
- package/dist/commands/employees.js +24 -80
- package/dist/commands/entity-configurations.d.ts +0 -1
- package/dist/commands/entity-configurations.js +22 -78
- package/dist/commands/event-processor-mappings.d.ts +0 -1
- package/dist/commands/event-processor-mappings.js +22 -78
- package/dist/commands/{files-internal.d.ts → files.d.ts} +1 -2
- package/dist/commands/{files-internal.js → files.js} +40 -90
- package/dist/commands/health.d.ts +0 -1
- package/dist/commands/health.js +22 -78
- package/dist/commands/inbox.d.ts +0 -1
- package/dist/commands/inbox.js +22 -78
- package/dist/commands/integrations.d.ts +0 -1
- package/dist/commands/integrations.js +22 -78
- package/dist/commands/item-categories.d.ts +0 -1
- package/dist/commands/item-categories.js +22 -78
- package/dist/commands/items.d.ts +0 -1
- package/dist/commands/items.js +24 -80
- package/dist/commands/journal-lines.d.ts +0 -1
- package/dist/commands/journal-lines.js +22 -78
- package/dist/commands/journals.d.ts +1 -1
- package/dist/commands/journals.js +29 -81
- package/dist/commands/ledgers.d.ts +0 -1
- package/dist/commands/ledgers.js +26 -79
- package/dist/commands/nango-integrations.d.ts +39 -0
- package/dist/commands/nango-integrations.js +1115 -0
- package/dist/commands/office-locations.d.ts +0 -1
- package/dist/commands/office-locations.js +22 -78
- package/dist/commands/payment-methods.d.ts +0 -1
- package/dist/commands/payment-methods.js +22 -78
- package/dist/commands/payment-runs.d.ts +0 -1
- package/dist/commands/payment-runs.js +24 -79
- package/dist/commands/payment-terms.d.ts +0 -1
- package/dist/commands/payment-terms.js +22 -78
- package/dist/commands/payments.d.ts +0 -1
- package/dist/commands/payments.js +22 -78
- package/dist/commands/price-lists.d.ts +0 -1
- package/dist/commands/price-lists.js +22 -78
- package/dist/commands/processor-mappings.d.ts +0 -1
- package/dist/commands/processor-mappings.js +22 -78
- package/dist/commands/processors.d.ts +0 -1
- package/dist/commands/processors.js +22 -78
- package/dist/commands/purchase-order-types.d.ts +0 -1
- package/dist/commands/purchase-order-types.js +22 -78
- package/dist/commands/purchase-orders.d.ts +1 -1
- package/dist/commands/purchase-orders.js +35 -84
- package/dist/commands/reports.d.ts +0 -1
- package/dist/commands/reports.js +23 -79
- package/dist/commands/salary-types.d.ts +0 -1
- package/dist/commands/salary-types.js +22 -78
- package/dist/commands/sales-invoices.d.ts +0 -1
- package/dist/commands/sales-invoices.js +38 -89
- package/dist/commands/sales-orders.d.ts +0 -1
- package/dist/commands/sales-orders.js +26 -82
- package/dist/commands/saved-views.d.ts +0 -1
- package/dist/commands/saved-views.js +22 -78
- package/dist/commands/scheduled-processor-mappings.d.ts +0 -1
- package/dist/commands/scheduled-processor-mappings.js +22 -78
- package/dist/commands/schedules.d.ts +0 -1
- package/dist/commands/schedules.js +22 -78
- package/dist/commands/switch.js +14 -7
- package/dist/commands/tag-configurations.d.ts +39 -0
- package/dist/commands/{documents.js → tag-configurations.js} +40 -96
- package/dist/commands/tags.d.ts +0 -1
- package/dist/commands/tags.js +22 -78
- package/dist/commands/tax-codes.d.ts +0 -1
- package/dist/commands/tax-codes.js +22 -78
- package/dist/commands/tax-matrix.d.ts +0 -1
- package/dist/commands/tax-matrix.js +22 -78
- package/dist/commands/tenants.d.ts +0 -1
- package/dist/commands/tenants.js +24 -79
- package/dist/commands/text-templates.d.ts +0 -1
- package/dist/commands/text-templates.js +22 -78
- package/dist/commands/tools.d.ts +0 -1
- package/dist/commands/tools.js +22 -78
- package/dist/commands/vat-declarations.d.ts +1 -1
- package/dist/commands/vat-declarations.js +28 -79
- package/dist/commands/vendor-invoices.d.ts +0 -1
- package/dist/commands/vendor-invoices.js +31 -86
- package/dist/commands/webhooks.d.ts +0 -1
- package/dist/commands/webhooks.js +22 -78
- package/dist/commands/workflows.d.ts +0 -1
- package/dist/commands/workflows.js +22 -78
- package/dist/lib/api-client.js +8 -6
- package/dist/lib/auth/constants.d.ts +11 -0
- package/dist/lib/auth/constants.js +11 -0
- package/dist/lib/auth/errors.d.ts +17 -0
- package/dist/lib/auth/errors.js +22 -0
- package/dist/lib/auth/flow.d.ts +27 -0
- package/dist/lib/auth/flow.js +163 -0
- package/dist/lib/auth/guards.d.ts +5 -0
- package/dist/lib/auth/guards.js +14 -0
- package/dist/lib/auth/http.d.ts +16 -0
- package/dist/lib/auth/http.js +49 -0
- package/dist/lib/auth/index.d.ts +49 -0
- package/dist/lib/auth/index.js +217 -0
- package/dist/lib/auth/keycloak-provider.d.ts +75 -0
- package/dist/lib/auth/keycloak-provider.js +215 -0
- package/dist/lib/auth/pages.d.ts +25 -0
- package/dist/lib/auth/pages.js +123 -0
- package/dist/lib/auth/pkce.d.ts +11 -0
- package/dist/lib/auth/pkce.js +17 -0
- package/dist/lib/auth/tokens.d.ts +54 -0
- package/dist/lib/auth/tokens.js +104 -0
- package/dist/lib/auth/types.d.ts +57 -0
- package/dist/lib/auth/types.js +1 -0
- package/dist/lib/auth/validated-url.d.ts +6 -0
- package/dist/lib/auth/validated-url.js +53 -0
- package/dist/lib/base-api-command.js +6 -4
- package/dist/lib/config.d.ts +44 -4
- package/dist/lib/config.js +55 -19
- package/oclif.manifest.json +1181 -330
- package/package.json +3 -2
- package/dist/lib/auth.d.ts +0 -35
- package/dist/lib/auth.js +0 -566
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -29,7 +29,7 @@ export default class TextTemplates extends Command {
|
|
|
29
29
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
30
30
|
};
|
|
31
31
|
static flags = {
|
|
32
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
32
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
33
33
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
34
34
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
35
35
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -43,7 +43,7 @@ export default class TextTemplates extends Command {
|
|
|
43
43
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
44
44
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
45
45
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
46
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
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
48
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
49
49
|
};
|
|
@@ -101,9 +101,9 @@ export default class TextTemplates extends Command {
|
|
|
101
101
|
}
|
|
102
102
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
103
103
|
if (!context)
|
|
104
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
105
|
-
if (!context
|
|
106
|
-
this.error(
|
|
104
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
105
|
+
if (!hasCredentials(context))
|
|
106
|
+
this.error(missingCredentialsMessage(context));
|
|
107
107
|
const queryParams = {};
|
|
108
108
|
if (flags.page)
|
|
109
109
|
queryParams.page = flags.page;
|
|
@@ -115,6 +115,8 @@ export default class TextTemplates extends Command {
|
|
|
115
115
|
queryParams.search = flags.search;
|
|
116
116
|
if (flags['sort-by'])
|
|
117
117
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
118
|
+
if (flags.fields)
|
|
119
|
+
queryParams.fields = flags.fields;
|
|
118
120
|
if (flags.query) {
|
|
119
121
|
try {
|
|
120
122
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -317,11 +319,6 @@ export default class TextTemplates extends Command {
|
|
|
317
319
|
output = obj[arrayKeys[0]];
|
|
318
320
|
}
|
|
319
321
|
}
|
|
320
|
-
// Filter fields if --fields flag is provided
|
|
321
|
-
if (flags.fields) {
|
|
322
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
323
|
-
output = this.filterFields(output, fieldList);
|
|
324
|
-
}
|
|
325
322
|
// Sanitize output if requested
|
|
326
323
|
if (flags.sanitize) {
|
|
327
324
|
output = this.sanitizeOutput(output);
|
|
@@ -346,9 +343,9 @@ export default class TextTemplates extends Command {
|
|
|
346
343
|
async runImport(flags) {
|
|
347
344
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
348
345
|
if (!context)
|
|
349
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
350
|
-
if (!context
|
|
351
|
-
this.error(
|
|
346
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
347
|
+
if (!hasCredentials(context))
|
|
348
|
+
this.error(missingCredentialsMessage(context));
|
|
352
349
|
// Get data from file, --data, or --set flags
|
|
353
350
|
let items = [];
|
|
354
351
|
if (flags.file) {
|
|
@@ -558,9 +555,9 @@ export default class TextTemplates extends Command {
|
|
|
558
555
|
async runExport(flags) {
|
|
559
556
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
560
557
|
if (!context)
|
|
561
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
562
|
-
if (!context
|
|
563
|
-
this.error(
|
|
558
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
559
|
+
if (!hasCredentials(context))
|
|
560
|
+
this.error(missingCredentialsMessage(context));
|
|
564
561
|
const listEndpoint = ENDPOINTS['list'];
|
|
565
562
|
if (!listEndpoint)
|
|
566
563
|
this.error('Export requires a list endpoint');
|
|
@@ -576,6 +573,8 @@ export default class TextTemplates extends Command {
|
|
|
576
573
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
577
574
|
if (flags.include)
|
|
578
575
|
baseParams.include = flags.include;
|
|
576
|
+
if (flags.fields)
|
|
577
|
+
baseParams.fields = flags.fields;
|
|
579
578
|
if (flags.query) {
|
|
580
579
|
try {
|
|
581
580
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -630,12 +629,7 @@ export default class TextTemplates extends Command {
|
|
|
630
629
|
}
|
|
631
630
|
}
|
|
632
631
|
process.stderr.write(' done\n');
|
|
633
|
-
// Filter fields if specified
|
|
634
632
|
let output = allItems;
|
|
635
|
-
if (flags.fields) {
|
|
636
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
637
|
-
output = this.filterFields(allItems, fieldList);
|
|
638
|
-
}
|
|
639
633
|
// Sanitize output if requested
|
|
640
634
|
if (flags.sanitize) {
|
|
641
635
|
output = this.sanitizeOutput(output);
|
|
@@ -652,9 +646,9 @@ export default class TextTemplates extends Command {
|
|
|
652
646
|
async runCamt053Import(flags) {
|
|
653
647
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
654
648
|
if (!context)
|
|
655
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
656
|
-
if (!context
|
|
657
|
-
this.error(
|
|
649
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
650
|
+
if (!hasCredentials(context))
|
|
651
|
+
this.error(missingCredentialsMessage(context));
|
|
658
652
|
if (!flags.file) {
|
|
659
653
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
660
654
|
}
|
|
@@ -742,9 +736,9 @@ export default class TextTemplates extends Command {
|
|
|
742
736
|
}
|
|
743
737
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
744
738
|
if (!context)
|
|
745
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
746
|
-
if (!context
|
|
747
|
-
this.error(
|
|
739
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
740
|
+
if (!hasCredentials(context))
|
|
741
|
+
this.error(missingCredentialsMessage(context));
|
|
748
742
|
// Get data from file, --data, or --set flags
|
|
749
743
|
let items = [];
|
|
750
744
|
if (flags.file) {
|
|
@@ -964,56 +958,6 @@ export default class TextTemplates extends Command {
|
|
|
964
958
|
return `\$${op}`;
|
|
965
959
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
966
960
|
}
|
|
967
|
-
filterFields(data, fields) {
|
|
968
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
969
|
-
const pick = (obj, keys) => {
|
|
970
|
-
// Group keys by their first segment so sibling sub-paths
|
|
971
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
972
|
-
// and don't clobber each other on merge.
|
|
973
|
-
const directKeys = new Set();
|
|
974
|
-
const nestedKeys = new Map();
|
|
975
|
-
for (const key of keys) {
|
|
976
|
-
if (key.split('.').some(isUnsafeKey))
|
|
977
|
-
continue;
|
|
978
|
-
if (key.includes('.')) {
|
|
979
|
-
const [first, ...rest] = key.split('.');
|
|
980
|
-
if (isUnsafeKey(first))
|
|
981
|
-
continue;
|
|
982
|
-
const list = nestedKeys.get(first);
|
|
983
|
-
if (list) {
|
|
984
|
-
list.push(rest.join('.'));
|
|
985
|
-
}
|
|
986
|
-
else {
|
|
987
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
else {
|
|
991
|
-
directKeys.add(key);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
const result = {};
|
|
995
|
-
for (const key of directKeys) {
|
|
996
|
-
if (key in obj)
|
|
997
|
-
result[key] = obj[key];
|
|
998
|
-
}
|
|
999
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1000
|
-
const val = obj[first];
|
|
1001
|
-
if (!val || typeof val !== 'object')
|
|
1002
|
-
continue;
|
|
1003
|
-
if (Array.isArray(val)) {
|
|
1004
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1005
|
-
}
|
|
1006
|
-
else {
|
|
1007
|
-
result[first] = pick(val, restKeys);
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
return result;
|
|
1011
|
-
};
|
|
1012
|
-
if (Array.isArray(data)) {
|
|
1013
|
-
return data.map(item => pick(item, fields));
|
|
1014
|
-
}
|
|
1015
|
-
return pick(data, fields);
|
|
1016
|
-
}
|
|
1017
961
|
sanitizeOutput(data) {
|
|
1018
962
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1019
963
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
package/dist/commands/tools.d.ts
CHANGED
package/dist/commands/tools.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = false;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
@@ -22,7 +22,7 @@ export default class Tools extends Command {
|
|
|
22
22
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
23
23
|
};
|
|
24
24
|
static flags = {
|
|
25
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
25
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
26
26
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
27
27
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
28
28
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -36,7 +36,7 @@ export default class Tools extends Command {
|
|
|
36
36
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
37
37
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
38
38
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
39
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
39
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
40
40
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
41
41
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
42
42
|
};
|
|
@@ -94,9 +94,9 @@ export default class Tools extends Command {
|
|
|
94
94
|
}
|
|
95
95
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
96
96
|
if (!context)
|
|
97
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
98
|
-
if (!context
|
|
99
|
-
this.error(
|
|
97
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
98
|
+
if (!hasCredentials(context))
|
|
99
|
+
this.error(missingCredentialsMessage(context));
|
|
100
100
|
const queryParams = {};
|
|
101
101
|
if (flags.page)
|
|
102
102
|
queryParams.page = flags.page;
|
|
@@ -108,6 +108,8 @@ export default class Tools extends Command {
|
|
|
108
108
|
queryParams.search = flags.search;
|
|
109
109
|
if (flags['sort-by'])
|
|
110
110
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
111
|
+
if (flags.fields)
|
|
112
|
+
queryParams.fields = flags.fields;
|
|
111
113
|
if (flags.query) {
|
|
112
114
|
try {
|
|
113
115
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -310,11 +312,6 @@ export default class Tools extends Command {
|
|
|
310
312
|
output = obj[arrayKeys[0]];
|
|
311
313
|
}
|
|
312
314
|
}
|
|
313
|
-
// Filter fields if --fields flag is provided
|
|
314
|
-
if (flags.fields) {
|
|
315
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
316
|
-
output = this.filterFields(output, fieldList);
|
|
317
|
-
}
|
|
318
315
|
// Sanitize output if requested
|
|
319
316
|
if (flags.sanitize) {
|
|
320
317
|
output = this.sanitizeOutput(output);
|
|
@@ -339,9 +336,9 @@ export default class Tools extends Command {
|
|
|
339
336
|
async runImport(flags) {
|
|
340
337
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
341
338
|
if (!context)
|
|
342
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
343
|
-
if (!context
|
|
344
|
-
this.error(
|
|
339
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
340
|
+
if (!hasCredentials(context))
|
|
341
|
+
this.error(missingCredentialsMessage(context));
|
|
345
342
|
// Get data from file, --data, or --set flags
|
|
346
343
|
let items = [];
|
|
347
344
|
if (flags.file) {
|
|
@@ -551,9 +548,9 @@ export default class Tools extends Command {
|
|
|
551
548
|
async runExport(flags) {
|
|
552
549
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
553
550
|
if (!context)
|
|
554
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
555
|
-
if (!context
|
|
556
|
-
this.error(
|
|
551
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
552
|
+
if (!hasCredentials(context))
|
|
553
|
+
this.error(missingCredentialsMessage(context));
|
|
557
554
|
const listEndpoint = ENDPOINTS['list'];
|
|
558
555
|
if (!listEndpoint)
|
|
559
556
|
this.error('Export requires a list endpoint');
|
|
@@ -569,6 +566,8 @@ export default class Tools extends Command {
|
|
|
569
566
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
570
567
|
if (flags.include)
|
|
571
568
|
baseParams.include = flags.include;
|
|
569
|
+
if (flags.fields)
|
|
570
|
+
baseParams.fields = flags.fields;
|
|
572
571
|
if (flags.query) {
|
|
573
572
|
try {
|
|
574
573
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -623,12 +622,7 @@ export default class Tools extends Command {
|
|
|
623
622
|
}
|
|
624
623
|
}
|
|
625
624
|
process.stderr.write(' done\n');
|
|
626
|
-
// Filter fields if specified
|
|
627
625
|
let output = allItems;
|
|
628
|
-
if (flags.fields) {
|
|
629
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
630
|
-
output = this.filterFields(allItems, fieldList);
|
|
631
|
-
}
|
|
632
626
|
// Sanitize output if requested
|
|
633
627
|
if (flags.sanitize) {
|
|
634
628
|
output = this.sanitizeOutput(output);
|
|
@@ -645,9 +639,9 @@ export default class Tools extends Command {
|
|
|
645
639
|
async runCamt053Import(flags) {
|
|
646
640
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
647
641
|
if (!context)
|
|
648
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
649
|
-
if (!context
|
|
650
|
-
this.error(
|
|
642
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
643
|
+
if (!hasCredentials(context))
|
|
644
|
+
this.error(missingCredentialsMessage(context));
|
|
651
645
|
if (!flags.file) {
|
|
652
646
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
653
647
|
}
|
|
@@ -735,9 +729,9 @@ export default class Tools extends Command {
|
|
|
735
729
|
}
|
|
736
730
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
737
731
|
if (!context)
|
|
738
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
739
|
-
if (!context
|
|
740
|
-
this.error(
|
|
732
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
733
|
+
if (!hasCredentials(context))
|
|
734
|
+
this.error(missingCredentialsMessage(context));
|
|
741
735
|
// Get data from file, --data, or --set flags
|
|
742
736
|
let items = [];
|
|
743
737
|
if (flags.file) {
|
|
@@ -957,56 +951,6 @@ export default class Tools extends Command {
|
|
|
957
951
|
return `\$${op}`;
|
|
958
952
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
959
953
|
}
|
|
960
|
-
filterFields(data, fields) {
|
|
961
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
962
|
-
const pick = (obj, keys) => {
|
|
963
|
-
// Group keys by their first segment so sibling sub-paths
|
|
964
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
965
|
-
// and don't clobber each other on merge.
|
|
966
|
-
const directKeys = new Set();
|
|
967
|
-
const nestedKeys = new Map();
|
|
968
|
-
for (const key of keys) {
|
|
969
|
-
if (key.split('.').some(isUnsafeKey))
|
|
970
|
-
continue;
|
|
971
|
-
if (key.includes('.')) {
|
|
972
|
-
const [first, ...rest] = key.split('.');
|
|
973
|
-
if (isUnsafeKey(first))
|
|
974
|
-
continue;
|
|
975
|
-
const list = nestedKeys.get(first);
|
|
976
|
-
if (list) {
|
|
977
|
-
list.push(rest.join('.'));
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
983
|
-
else {
|
|
984
|
-
directKeys.add(key);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
const result = {};
|
|
988
|
-
for (const key of directKeys) {
|
|
989
|
-
if (key in obj)
|
|
990
|
-
result[key] = obj[key];
|
|
991
|
-
}
|
|
992
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
993
|
-
const val = obj[first];
|
|
994
|
-
if (!val || typeof val !== 'object')
|
|
995
|
-
continue;
|
|
996
|
-
if (Array.isArray(val)) {
|
|
997
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
998
|
-
}
|
|
999
|
-
else {
|
|
1000
|
-
result[first] = pick(val, restKeys);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
return result;
|
|
1004
|
-
};
|
|
1005
|
-
if (Array.isArray(data)) {
|
|
1006
|
-
return data.map(item => pick(item, fields));
|
|
1007
|
-
}
|
|
1008
|
-
return pick(data, fields);
|
|
1009
|
-
}
|
|
1010
954
|
sanitizeOutput(data) {
|
|
1011
955
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1012
956
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -15,6 +15,7 @@ export default class VatDeclarations extends Command {
|
|
|
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
17
|
'field-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'notice-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
19
|
'file-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
20
|
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
21
|
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -33,7 +34,6 @@ export default class VatDeclarations extends Command {
|
|
|
33
34
|
private runCamt053Import;
|
|
34
35
|
private runNestedImport;
|
|
35
36
|
private parseFilterValue;
|
|
36
|
-
private filterFields;
|
|
37
37
|
private sanitizeOutput;
|
|
38
38
|
private getColumns;
|
|
39
39
|
private getValue;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
|
|
3
|
-
import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
|
|
3
|
+
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
4
|
// Add 'import' action if both create and update exist
|
|
5
5
|
const HAS_IMPORT = true;
|
|
6
6
|
const HAS_EXPORT = true;
|
|
7
7
|
const HAS_CAMT053 = false;
|
|
8
8
|
const NESTED_IMPORTS = ["files"];
|
|
9
|
-
const SUBCOMMANDS = [...["list", "create", "preview", "get", "update", "delete", "regenerate", "replace", "fields-contributions", "fields-contributions-export", "approve", "mark-as-filed", "xml", "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 = [...["list", "create", "preview", "get", "update", "delete", "regenerate", "replace", "fields-contributions", "fields-contributions-export", "approve", "notices-dismiss", "notices-restore", "mark-as-filed", "xml", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-payments", "create-payments"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
11
|
'list': { method: 'GET', path: '/v1/vat-declarations', summary: 'List VAT reports (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
12
|
'create': { method: 'POST', path: '/v1/vat-declarations', summary: 'Create a VAT declaration report (always async-accepted)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
@@ -19,6 +19,8 @@ const ENDPOINTS = {
|
|
|
19
19
|
'fields-contributions': { method: 'GET', path: '/v1/vat-declarations/{id}/fields/{fieldId}/contributions', summary: 'Drill into the contributions for a single Ziffer', pathParams: ['id', 'fieldId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
20
|
'fields-contributions-export': { method: 'GET', path: '/v1/vat-declarations/{id}/fields/{fieldId}/contributions/export', summary: 'Export the drill-down result set as an Excel workbook', pathParams: ['id', 'fieldId'], hasBody: false, isMultipart: false, isBinaryResponse: true, bodyArrayFields: [] },
|
|
21
21
|
'approve': { method: 'POST', path: '/v1/vat-declarations/{id}/approve', summary: 'Approve a VAT report and produce the eCH-0217 XML submission file.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
+
'notices-dismiss': { method: 'POST', path: '/v1/vat-declarations/{id}/notices/{noticeId}/dismiss', summary: 'Dismiss a generation notice with a mandatory reason.', pathParams: ['id', 'noticeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
|
+
'notices-restore': { method: 'POST', path: '/v1/vat-declarations/{id}/notices/{noticeId}/restore', summary: 'Restore a previously dismissed generation notice.', pathParams: ['id', 'noticeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
24
|
'mark-as-filed': { method: 'POST', path: '/v1/vat-declarations/{id}/mark-as-filed', summary: 'Mark a FINALIZED VAT declaration as filed.', pathParams: ['id'], hasBody: true, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
25
|
'xml': { method: 'GET', path: '/v1/vat-declarations/{id}/xml', summary: 'Download the eCH-0217 XML submission file for a FINALIZED or FILED VAT report.', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: true, bodyArrayFields: [] },
|
|
24
26
|
'list-files': { method: 'GET', path: '/v1/vat-declarations/{parentId}/files', summary: 'List file attachments for a VAT declaration', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
@@ -27,6 +29,8 @@ const ENDPOINTS = {
|
|
|
27
29
|
'update-files': { method: 'PATCH', path: '/v1/vat-declarations/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a VAT declaration', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
28
30
|
'delete-files': { method: 'DELETE', path: '/v1/vat-declarations/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a VAT declaration', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
29
31
|
'files-download': { method: 'GET', path: '/v1/vat-declarations/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a VAT declaration', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
32
|
+
'list-payments': { method: 'GET', path: '/v1/vat-declarations/{vatDeclarationId}/payments', summary: 'Get all payments for a VAT declaration', pathParams: ['vatDeclarationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
33
|
+
'create-payments': { method: 'POST', path: '/v1/vat-declarations/{vatDeclarationId}/payments', summary: 'Create the payment for a filed VAT declaration', pathParams: ['vatDeclarationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
30
34
|
};
|
|
31
35
|
export default class VatDeclarations extends Command {
|
|
32
36
|
static description = 'Manage vat declarations';
|
|
@@ -43,7 +47,7 @@ export default class VatDeclarations extends Command {
|
|
|
43
47
|
id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
|
|
44
48
|
};
|
|
45
49
|
static flags = {
|
|
46
|
-
context: Flags.string({ char: 'c', description: 'Context to use' }),
|
|
50
|
+
context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
|
|
47
51
|
output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
|
|
48
52
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
49
53
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
@@ -51,6 +55,7 @@ export default class VatDeclarations extends Command {
|
|
|
51
55
|
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
52
56
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
53
57
|
'field-id': Flags.string({ description: 'Path param: fieldId' }),
|
|
58
|
+
'notice-id': Flags.string({ description: 'Path param: noticeId' }),
|
|
54
59
|
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
55
60
|
page: Flags.string({ description: 'Page number' }),
|
|
56
61
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -59,7 +64,7 @@ export default class VatDeclarations extends Command {
|
|
|
59
64
|
'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
|
|
60
65
|
filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
|
|
61
66
|
query: Flags.string({ description: 'Additional query params as JSON' }),
|
|
62
|
-
fields: Flags.string({ description: 'Comma-separated list of fields to
|
|
67
|
+
fields: Flags.string({ description: 'Comma-separated list of fields to return, applied by the API (e.g. --fields=id,name,status)' }),
|
|
63
68
|
sanitize: Flags.boolean({ description: 'Remove null values, audit fields, and duplicate UUIDs from output' }),
|
|
64
69
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
65
70
|
};
|
|
@@ -117,9 +122,9 @@ export default class VatDeclarations extends Command {
|
|
|
117
122
|
}
|
|
118
123
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
119
124
|
if (!context)
|
|
120
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
121
|
-
if (!context
|
|
122
|
-
this.error(
|
|
125
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
126
|
+
if (!hasCredentials(context))
|
|
127
|
+
this.error(missingCredentialsMessage(context));
|
|
123
128
|
const queryParams = {};
|
|
124
129
|
if (flags.page)
|
|
125
130
|
queryParams.page = flags.page;
|
|
@@ -131,6 +136,8 @@ export default class VatDeclarations extends Command {
|
|
|
131
136
|
queryParams.search = flags.search;
|
|
132
137
|
if (flags['sort-by'])
|
|
133
138
|
queryParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
139
|
+
if (flags.fields)
|
|
140
|
+
queryParams.fields = flags.fields;
|
|
134
141
|
if (flags.query) {
|
|
135
142
|
try {
|
|
136
143
|
Object.assign(queryParams, JSON.parse(flags.query));
|
|
@@ -333,11 +340,6 @@ export default class VatDeclarations extends Command {
|
|
|
333
340
|
output = obj[arrayKeys[0]];
|
|
334
341
|
}
|
|
335
342
|
}
|
|
336
|
-
// Filter fields if --fields flag is provided
|
|
337
|
-
if (flags.fields) {
|
|
338
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
339
|
-
output = this.filterFields(output, fieldList);
|
|
340
|
-
}
|
|
341
343
|
// Sanitize output if requested
|
|
342
344
|
if (flags.sanitize) {
|
|
343
345
|
output = this.sanitizeOutput(output);
|
|
@@ -362,9 +364,9 @@ export default class VatDeclarations extends Command {
|
|
|
362
364
|
async runImport(flags) {
|
|
363
365
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
364
366
|
if (!context)
|
|
365
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
366
|
-
if (!context
|
|
367
|
-
this.error(
|
|
367
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
368
|
+
if (!hasCredentials(context))
|
|
369
|
+
this.error(missingCredentialsMessage(context));
|
|
368
370
|
// Get data from file, --data, or --set flags
|
|
369
371
|
let items = [];
|
|
370
372
|
if (flags.file) {
|
|
@@ -574,9 +576,9 @@ export default class VatDeclarations extends Command {
|
|
|
574
576
|
async runExport(flags) {
|
|
575
577
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
576
578
|
if (!context)
|
|
577
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
578
|
-
if (!context
|
|
579
|
-
this.error(
|
|
579
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
580
|
+
if (!hasCredentials(context))
|
|
581
|
+
this.error(missingCredentialsMessage(context));
|
|
580
582
|
const listEndpoint = ENDPOINTS['list'];
|
|
581
583
|
if (!listEndpoint)
|
|
582
584
|
this.error('Export requires a list endpoint');
|
|
@@ -592,6 +594,8 @@ export default class VatDeclarations extends Command {
|
|
|
592
594
|
baseParams.sortBy = normalizeSortBy(flags['sort-by']);
|
|
593
595
|
if (flags.include)
|
|
594
596
|
baseParams.include = flags.include;
|
|
597
|
+
if (flags.fields)
|
|
598
|
+
baseParams.fields = flags.fields;
|
|
595
599
|
if (flags.query) {
|
|
596
600
|
try {
|
|
597
601
|
Object.assign(baseParams, JSON.parse(flags.query));
|
|
@@ -646,12 +650,7 @@ export default class VatDeclarations extends Command {
|
|
|
646
650
|
}
|
|
647
651
|
}
|
|
648
652
|
process.stderr.write(' done\n');
|
|
649
|
-
// Filter fields if specified
|
|
650
653
|
let output = allItems;
|
|
651
|
-
if (flags.fields) {
|
|
652
|
-
const fieldList = flags.fields.split(',').map(f => f.trim());
|
|
653
|
-
output = this.filterFields(allItems, fieldList);
|
|
654
|
-
}
|
|
655
654
|
// Sanitize output if requested
|
|
656
655
|
if (flags.sanitize) {
|
|
657
656
|
output = this.sanitizeOutput(output);
|
|
@@ -668,9 +667,9 @@ export default class VatDeclarations extends Command {
|
|
|
668
667
|
async runCamt053Import(flags) {
|
|
669
668
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
670
669
|
if (!context)
|
|
671
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
672
|
-
if (!context
|
|
673
|
-
this.error(
|
|
670
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
671
|
+
if (!hasCredentials(context))
|
|
672
|
+
this.error(missingCredentialsMessage(context));
|
|
674
673
|
if (!flags.file) {
|
|
675
674
|
this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
|
|
676
675
|
}
|
|
@@ -758,9 +757,9 @@ export default class VatDeclarations extends Command {
|
|
|
758
757
|
}
|
|
759
758
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
760
759
|
if (!context)
|
|
761
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
762
|
-
if (!context
|
|
763
|
-
this.error(
|
|
760
|
+
this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
|
|
761
|
+
if (!hasCredentials(context))
|
|
762
|
+
this.error(missingCredentialsMessage(context));
|
|
764
763
|
// Get data from file, --data, or --set flags
|
|
765
764
|
let items = [];
|
|
766
765
|
if (flags.file) {
|
|
@@ -980,56 +979,6 @@ export default class VatDeclarations extends Command {
|
|
|
980
979
|
return `\$${op}`;
|
|
981
980
|
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
982
981
|
}
|
|
983
|
-
filterFields(data, fields) {
|
|
984
|
-
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
985
|
-
const pick = (obj, keys) => {
|
|
986
|
-
// Group keys by their first segment so sibling sub-paths
|
|
987
|
-
// (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
|
|
988
|
-
// and don't clobber each other on merge.
|
|
989
|
-
const directKeys = new Set();
|
|
990
|
-
const nestedKeys = new Map();
|
|
991
|
-
for (const key of keys) {
|
|
992
|
-
if (key.split('.').some(isUnsafeKey))
|
|
993
|
-
continue;
|
|
994
|
-
if (key.includes('.')) {
|
|
995
|
-
const [first, ...rest] = key.split('.');
|
|
996
|
-
if (isUnsafeKey(first))
|
|
997
|
-
continue;
|
|
998
|
-
const list = nestedKeys.get(first);
|
|
999
|
-
if (list) {
|
|
1000
|
-
list.push(rest.join('.'));
|
|
1001
|
-
}
|
|
1002
|
-
else {
|
|
1003
|
-
nestedKeys.set(first, [rest.join('.')]);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
else {
|
|
1007
|
-
directKeys.add(key);
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
const result = {};
|
|
1011
|
-
for (const key of directKeys) {
|
|
1012
|
-
if (key in obj)
|
|
1013
|
-
result[key] = obj[key];
|
|
1014
|
-
}
|
|
1015
|
-
for (const [first, restKeys] of nestedKeys) {
|
|
1016
|
-
const val = obj[first];
|
|
1017
|
-
if (!val || typeof val !== 'object')
|
|
1018
|
-
continue;
|
|
1019
|
-
if (Array.isArray(val)) {
|
|
1020
|
-
result[first] = val.map(item => pick(item, restKeys));
|
|
1021
|
-
}
|
|
1022
|
-
else {
|
|
1023
|
-
result[first] = pick(val, restKeys);
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
return result;
|
|
1027
|
-
};
|
|
1028
|
-
if (Array.isArray(data)) {
|
|
1029
|
-
return data.map(item => pick(item, fields));
|
|
1030
|
-
}
|
|
1031
|
-
return pick(data, fields);
|
|
1032
|
-
}
|
|
1033
982
|
sanitizeOutput(data) {
|
|
1034
983
|
const auditFields = ['_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy'];
|
|
1035
984
|
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|