@aderis-erp/cli 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/access-groups.js +42 -8
- package/dist/commands/account-transaction-allocations.js +38 -4
- package/dist/commands/account-transactions.d.ts +2 -0
- package/dist/commands/account-transactions.js +68 -32
- package/dist/commands/accounts.js +46 -12
- package/dist/commands/agent-platform.js +37 -3
- package/dist/commands/agent-runs.js +49 -15
- package/dist/commands/analytics.js +39 -5
- package/dist/commands/api-clients.js +47 -13
- package/dist/commands/api-keys.js +40 -6
- package/dist/commands/async-jobs.js +45 -11
- package/dist/commands/audit-log.js +38 -4
- package/dist/commands/bank-accounts.js +54 -20
- package/dist/commands/bank-integrations.js +56 -22
- package/dist/commands/business-partners.js +77 -43
- package/dist/commands/chat.js +43 -9
- package/dist/commands/credit-card-accounts.js +57 -23
- package/dist/commands/currencies.js +37 -3
- package/dist/commands/custody-accounts.js +41 -7
- package/dist/commands/dashboards.js +52 -18
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +1 -0
- package/dist/commands/document-checksums.js +38 -3
- package/dist/commands/dunning-configs.js +41 -7
- package/dist/commands/dunning-reminders.js +44 -10
- package/dist/commands/dunning-runs.js +37 -3
- package/dist/commands/email-transactions.js +39 -5
- package/dist/commands/employees.js +77 -43
- package/dist/commands/entity-configurations.js +39 -5
- package/dist/commands/event-mapping-rules.js +37 -3
- package/dist/commands/event-processor-mappings.js +41 -7
- package/dist/commands/files.js +48 -14
- package/dist/commands/financial-instrument-transactions.d.ts +56 -0
- package/dist/commands/financial-instrument-transactions.js +1369 -0
- package/dist/commands/financial-instrument-types.js +41 -7
- package/dist/commands/financial-instruments.js +41 -7
- package/dist/commands/health.js +41 -7
- package/dist/commands/imports.js +39 -5
- package/dist/commands/inbox.js +42 -8
- package/dist/commands/integrations.js +39 -5
- package/dist/commands/item-categories.js +41 -7
- package/dist/commands/items.js +42 -8
- package/dist/commands/journal-lines.js +37 -3
- package/dist/commands/journals.js +61 -27
- package/dist/commands/kpis.js +44 -10
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.js +37 -3
- package/dist/commands/office-locations.js +41 -7
- package/dist/commands/payment-methods.js +46 -12
- package/dist/commands/payment-runs.js +54 -20
- package/dist/commands/payment-terms.js +42 -8
- package/dist/commands/payments.js +43 -9
- package/dist/commands/payroll-runs.js +71 -37
- package/dist/commands/permissions.js +37 -3
- package/dist/commands/price-lists.js +48 -14
- package/dist/commands/processor-mappings.js +40 -6
- package/dist/commands/processors.js +46 -12
- package/dist/commands/purchase-order-types.js +41 -7
- package/dist/commands/purchase-orders.js +60 -26
- package/dist/commands/reports.js +43 -8
- package/dist/commands/roles.js +40 -6
- package/dist/commands/salary-types.js +41 -7
- package/dist/commands/sales-invoices.js +85 -51
- package/dist/commands/sales-orders.js +69 -35
- package/dist/commands/saved-views.js +39 -5
- package/dist/commands/scheduled-processor-mappings.js +41 -7
- package/dist/commands/schedules.js +45 -11
- package/dist/commands/settings.js +38 -4
- package/dist/commands/tags.js +42 -8
- package/dist/commands/tax-codes.js +44 -10
- package/dist/commands/tax-matrix.js +41 -7
- package/dist/commands/templates.js +49 -15
- package/dist/commands/tenants.js +44 -10
- package/dist/commands/tools.js +38 -4
- package/dist/commands/users.js +58 -24
- package/dist/commands/vat-declarations.js +61 -27
- package/dist/commands/vendor-invoices.js +81 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.js +37 -3
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.js +2 -0
- package/oclif.manifest.json +199 -2
- package/package.json +9 -3
package/dist/commands/tenants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,14 +12,14 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "logo", "icon", "update-identity-provider"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/tenants', summary: 'Get all tenants with pagination (admin only)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/tenants', summary: 'Create a new tenant (admin only)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['supportedLocales', 'allowedSenders', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'salesOrderRecipientCc', 'salesOrderRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/tenants/{id}', summary: 'Get a tenant by ID (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/tenants/{id}', summary: 'Update a tenant (own tenant or admin)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['supportedLocales', 'allowedSenders', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'salesOrderRecipientCc', 'salesOrderRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/tenants/{id}', summary: 'Delete a tenant (admin only)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'logo': { method: 'POST', path: '/v1/tenants/{id}/logo', summary: 'Upload the tenant logo to the public bucket and set logoUrl (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'icon': { method: 'POST', path: '/v1/tenants/{id}/icon', summary: 'Upload the tenant icon to the public bucket and set iconUrl (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'update-identity-provider': { method: 'PUT', path: '/v1/tenants/{id}/identity-provider', summary: 'Synchronize a tenant with the identity provider (admin only)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/tenants', summary: 'Get all tenants with pagination (admin only)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/tenants', summary: 'Create a new tenant (admin only)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['supportedLocales', 'allowedSenders', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'salesOrderRecipientCc', 'salesOrderRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/tenants/{id}', summary: 'Get a tenant by ID (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/tenants/{id}', summary: 'Update a tenant (own tenant or admin)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['supportedLocales', 'allowedSenders', 'salesInvoiceRecipientCc', 'salesInvoiceRecipientBcc', 'salesOrderRecipientCc', 'salesOrderRecipientBcc', 'deliveryNoteRecipientCc', 'deliveryNoteRecipientBcc'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/tenants/{id}', summary: 'Delete a tenant (admin only)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'logo': { method: 'POST', path: '/v1/tenants/{id}/logo', summary: 'Upload the tenant logo to the public bucket and set logoUrl (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'icon': { method: 'POST', path: '/v1/tenants/{id}/icon', summary: 'Upload the tenant icon to the public bucket and set iconUrl (own tenant or admin)', pathParams: ['id'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'update-identity-provider': { method: 'PUT', path: '/v1/tenants/{id}/identity-provider', summary: 'Synchronize a tenant with the identity provider (admin only)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
23
|
};
|
|
23
24
|
export default class Tenants extends Command {
|
|
24
25
|
static description = 'Manage tenants';
|
|
@@ -40,7 +41,7 @@ export default class Tenants extends Command {
|
|
|
40
41
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
41
42
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
42
43
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
43
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
44
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
44
45
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
45
46
|
page: Flags.string({ description: 'Page number' }),
|
|
46
47
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -171,6 +172,17 @@ export default class Tenants extends Command {
|
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
174
|
}
|
|
175
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
176
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
177
|
+
for (const param of endpoint.specParams) {
|
|
178
|
+
const value = flags[param.flag];
|
|
179
|
+
if (value === undefined || value === '') {
|
|
180
|
+
if (param.required)
|
|
181
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
queryParams[param.name] = value;
|
|
185
|
+
}
|
|
174
186
|
let data;
|
|
175
187
|
if (endpoint.isMultipart) {
|
|
176
188
|
if (!flags.file)
|
|
@@ -191,6 +203,25 @@ export default class Tenants extends Command {
|
|
|
191
203
|
}
|
|
192
204
|
data = form;
|
|
193
205
|
}
|
|
206
|
+
else if (endpoint.bodyMediaType) {
|
|
207
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
208
|
+
// verbatim, under the content type the endpoint asks for.
|
|
209
|
+
if (flags.file) {
|
|
210
|
+
const fsModule = await import('node:fs');
|
|
211
|
+
try {
|
|
212
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else if (flags.data) {
|
|
219
|
+
data = flags.data;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
194
225
|
else if (endpoint.hasBody) {
|
|
195
226
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
196
227
|
// input file — skip the read-as-body branch.
|
|
@@ -286,7 +317,7 @@ export default class Tenants extends Command {
|
|
|
286
317
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
287
318
|
}
|
|
288
319
|
else if (data) {
|
|
289
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
320
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
290
321
|
}
|
|
291
322
|
process.stderr.write('\n');
|
|
292
323
|
}
|
|
@@ -300,6 +331,7 @@ export default class Tenants extends Command {
|
|
|
300
331
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
301
332
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
302
333
|
data,
|
|
334
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
303
335
|
contextName: flags.context,
|
|
304
336
|
binary: true,
|
|
305
337
|
});
|
|
@@ -325,6 +357,7 @@ export default class Tenants extends Command {
|
|
|
325
357
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
326
358
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
327
359
|
data,
|
|
360
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
328
361
|
contextName: flags.context,
|
|
329
362
|
binary: true,
|
|
330
363
|
});
|
|
@@ -345,6 +378,7 @@ export default class Tenants extends Command {
|
|
|
345
378
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
346
379
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
347
380
|
data,
|
|
381
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
348
382
|
contextName: flags.context,
|
|
349
383
|
acceptAny: true,
|
|
350
384
|
});
|
package/dist/commands/tools.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,8 +12,8 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "find"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/tools', summary: 'List all available tools', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'find': { method: 'GET', path: '/v1/tools/{name}', summary: 'Get a single tool by canonical name', pathParams: ['name'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/tools', summary: 'List all available tools', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'find': { method: 'GET', path: '/v1/tools/{name}', summary: 'Get a single tool by canonical name', pathParams: ['name'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
17
|
};
|
|
17
18
|
export default class Tools extends Command {
|
|
18
19
|
static description = 'Manage tools';
|
|
@@ -30,7 +31,7 @@ export default class Tools extends Command {
|
|
|
30
31
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
31
32
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
32
33
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
33
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
34
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
34
35
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
35
36
|
page: Flags.string({ description: 'Page number' }),
|
|
36
37
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -161,6 +162,17 @@ export default class Tools extends Command {
|
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
}
|
|
165
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
166
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
167
|
+
for (const param of endpoint.specParams) {
|
|
168
|
+
const value = flags[param.flag];
|
|
169
|
+
if (value === undefined || value === '') {
|
|
170
|
+
if (param.required)
|
|
171
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
queryParams[param.name] = value;
|
|
175
|
+
}
|
|
164
176
|
let data;
|
|
165
177
|
if (endpoint.isMultipart) {
|
|
166
178
|
if (!flags.file)
|
|
@@ -181,6 +193,25 @@ export default class Tools extends Command {
|
|
|
181
193
|
}
|
|
182
194
|
data = form;
|
|
183
195
|
}
|
|
196
|
+
else if (endpoint.bodyMediaType) {
|
|
197
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
198
|
+
// verbatim, under the content type the endpoint asks for.
|
|
199
|
+
if (flags.file) {
|
|
200
|
+
const fsModule = await import('node:fs');
|
|
201
|
+
try {
|
|
202
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if (flags.data) {
|
|
209
|
+
data = flags.data;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
184
215
|
else if (endpoint.hasBody) {
|
|
185
216
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
186
217
|
// input file — skip the read-as-body branch.
|
|
@@ -276,7 +307,7 @@ export default class Tools extends Command {
|
|
|
276
307
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
277
308
|
}
|
|
278
309
|
else if (data) {
|
|
279
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
310
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
280
311
|
}
|
|
281
312
|
process.stderr.write('\n');
|
|
282
313
|
}
|
|
@@ -290,6 +321,7 @@ export default class Tools extends Command {
|
|
|
290
321
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
291
322
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
292
323
|
data,
|
|
324
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
293
325
|
contextName: flags.context,
|
|
294
326
|
binary: true,
|
|
295
327
|
});
|
|
@@ -315,6 +347,7 @@ export default class Tools extends Command {
|
|
|
315
347
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
316
348
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
317
349
|
data,
|
|
350
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
318
351
|
contextName: flags.context,
|
|
319
352
|
binary: true,
|
|
320
353
|
});
|
|
@@ -335,6 +368,7 @@ export default class Tools extends Command {
|
|
|
335
368
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
336
369
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
337
370
|
data,
|
|
371
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
338
372
|
contextName: flags.context,
|
|
339
373
|
acceptAny: true,
|
|
340
374
|
});
|
package/dist/commands/users.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,28 +12,28 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["roles"];
|
|
12
13
|
const SUBCOMMANDS = [...["list-invitations", "create-invitations", "send-invitations-resend", "delete-invitations", "list", "create", "get", "update", "delete", "get-credentials", "password-reset", "delete-credentials-mfa", "delete-credentials-otp", "delete-credentials-passkeys", "delete-identity-providers", "permissions", "list-roles", "create-roles", "update-roles", "delete-roles", "disable", "enable"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list-invitations': { method: 'GET', path: '/v1/users/invitations', summary: 'List the invitations still waiting to be accepted', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create-invitations': { method: 'POST', path: '/v1/users/invitations', summary: 'Invite a person who has no Aderis login yet', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'send-invitations-resend': { method: 'POST', path: '/v1/users/invitations/{invitationId}/resend', summary: 'Send the invitation mail again', pathParams: ['invitationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'delete-invitations': { method: 'DELETE', path: '/v1/users/invitations/{invitationId}', summary: 'Withdraw an invitation', pathParams: ['invitationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'list': { method: 'GET', path: '/v1/users', summary: 'List the people of the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'create': { method: 'POST', path: '/v1/users', summary: 'Give an existing login access to this tenant', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['roleIds'] },
|
|
20
|
-
'get': { method: 'GET', path: '/v1/users/{userId}', summary: 'Read one person', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'update': { method: 'PATCH', path: '/v1/users/{userId}', summary: 'Change one person', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'delete': { method: 'DELETE', path: '/v1/users/{userId}', summary: 'Remove one person from this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'get-credentials': { method: 'GET', path: '/v1/users/{userId}/credentials', summary: 'Read a tenant member’s sign-in methods', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'password-reset': { method: 'POST', path: '/v1/users/{userId}/password-reset', summary: 'Send a password-reset email', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'delete-credentials-mfa': { method: 'DELETE', path: '/v1/users/{userId}/credentials/mfa', summary: 'Reset a tenant member’s second factors', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'delete-credentials-otp': { method: 'DELETE', path: '/v1/users/{userId}/credentials/otp', summary: 'Reset a tenant member’s OTP factors', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'delete-credentials-passkeys': { method: 'DELETE', path: '/v1/users/{userId}/credentials/passkeys/{credentialId}', summary: 'Remove a tenant member’s passwordless passkey', pathParams: ['userId', 'credentialId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'delete-identity-providers': { method: 'DELETE', path: '/v1/users/{userId}/identity-providers/{provider}', summary: 'Unlink a tenant member’s external sign-in', pathParams: ['userId', 'provider'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'permissions': { method: 'GET', path: '/v1/users/{userId}/permissions', summary: 'Read what one person may do here', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'list-roles': { method: 'GET', path: '/v1/users/{userId}/roles', summary: 'Read the roles one person holds here', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'create-roles': { method: 'POST', path: '/v1/users/{userId}/roles', summary: 'Give one person one more role', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'update-roles': { method: 'PUT', path: '/v1/users/{userId}/roles', summary: 'Replace the roles one person holds here', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['roleIds'] },
|
|
33
|
-
'delete-roles': { method: 'DELETE', path: '/v1/users/{userId}/roles/{roleId}', summary: 'Take one role away from one person', pathParams: ['userId', 'roleId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'disable': { method: 'POST', path: '/v1/users/{userId}/disable', summary: 'Disable one person in this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'enable': { method: 'POST', path: '/v1/users/{userId}/enable', summary: 'Enable one person in this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list-invitations': { method: 'GET', path: '/v1/users/invitations', summary: 'List the invitations still waiting to be accepted', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create-invitations': { method: 'POST', path: '/v1/users/invitations', summary: 'Invite a person who has no Aderis login yet', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'send-invitations-resend': { method: 'POST', path: '/v1/users/invitations/{invitationId}/resend', summary: 'Send the invitation mail again', pathParams: ['invitationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'delete-invitations': { method: 'DELETE', path: '/v1/users/invitations/{invitationId}', summary: 'Withdraw an invitation', pathParams: ['invitationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'list': { method: 'GET', path: '/v1/users', summary: 'List the people of the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'create': { method: 'POST', path: '/v1/users', summary: 'Give an existing login access to this tenant', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['roleIds'], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'get': { method: 'GET', path: '/v1/users/{userId}', summary: 'Read one person', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'update': { method: 'PATCH', path: '/v1/users/{userId}', summary: 'Change one person', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'delete': { method: 'DELETE', path: '/v1/users/{userId}', summary: 'Remove one person from this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'get-credentials': { method: 'GET', path: '/v1/users/{userId}/credentials', summary: 'Read a tenant member’s sign-in methods', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'password-reset': { method: 'POST', path: '/v1/users/{userId}/password-reset', summary: 'Send a password-reset email', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'delete-credentials-mfa': { method: 'DELETE', path: '/v1/users/{userId}/credentials/mfa', summary: 'Reset a tenant member’s second factors', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'delete-credentials-otp': { method: 'DELETE', path: '/v1/users/{userId}/credentials/otp', summary: 'Reset a tenant member’s OTP factors', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'delete-credentials-passkeys': { method: 'DELETE', path: '/v1/users/{userId}/credentials/passkeys/{credentialId}', summary: 'Remove a tenant member’s passwordless passkey', pathParams: ['userId', 'credentialId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'delete-identity-providers': { method: 'DELETE', path: '/v1/users/{userId}/identity-providers/{provider}', summary: 'Unlink a tenant member’s external sign-in', pathParams: ['userId', 'provider'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'permissions': { method: 'GET', path: '/v1/users/{userId}/permissions', summary: 'Read what one person may do here', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'list-roles': { method: 'GET', path: '/v1/users/{userId}/roles', summary: 'Read the roles one person holds here', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'create-roles': { method: 'POST', path: '/v1/users/{userId}/roles', summary: 'Give one person one more role', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'update-roles': { method: 'PUT', path: '/v1/users/{userId}/roles', summary: 'Replace the roles one person holds here', pathParams: ['userId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['roleIds'], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'delete-roles': { method: 'DELETE', path: '/v1/users/{userId}/roles/{roleId}', summary: 'Take one role away from one person', pathParams: ['userId', 'roleId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'disable': { method: 'POST', path: '/v1/users/{userId}/disable', summary: 'Disable one person in this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'enable': { method: 'POST', path: '/v1/users/{userId}/enable', summary: 'Enable one person in this tenant', pathParams: ['userId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
37
|
};
|
|
37
38
|
export default class Users extends Command {
|
|
38
39
|
static description = 'Manage users';
|
|
@@ -54,7 +55,7 @@ export default class Users extends Command {
|
|
|
54
55
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
55
56
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
56
57
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
57
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
58
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
58
59
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
59
60
|
'credential-id': Flags.string({ description: 'Path param: credentialId' }),
|
|
60
61
|
'provider': Flags.string({ description: 'Path param: provider' }),
|
|
@@ -188,6 +189,17 @@ export default class Users extends Command {
|
|
|
188
189
|
}
|
|
189
190
|
}
|
|
190
191
|
}
|
|
192
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
193
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
194
|
+
for (const param of endpoint.specParams) {
|
|
195
|
+
const value = flags[param.flag];
|
|
196
|
+
if (value === undefined || value === '') {
|
|
197
|
+
if (param.required)
|
|
198
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
queryParams[param.name] = value;
|
|
202
|
+
}
|
|
191
203
|
let data;
|
|
192
204
|
if (endpoint.isMultipart) {
|
|
193
205
|
if (!flags.file)
|
|
@@ -208,6 +220,25 @@ export default class Users extends Command {
|
|
|
208
220
|
}
|
|
209
221
|
data = form;
|
|
210
222
|
}
|
|
223
|
+
else if (endpoint.bodyMediaType) {
|
|
224
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
225
|
+
// verbatim, under the content type the endpoint asks for.
|
|
226
|
+
if (flags.file) {
|
|
227
|
+
const fsModule = await import('node:fs');
|
|
228
|
+
try {
|
|
229
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
else if (flags.data) {
|
|
236
|
+
data = flags.data;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
211
242
|
else if (endpoint.hasBody) {
|
|
212
243
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
213
244
|
// input file — skip the read-as-body branch.
|
|
@@ -303,7 +334,7 @@ export default class Users extends Command {
|
|
|
303
334
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
304
335
|
}
|
|
305
336
|
else if (data) {
|
|
306
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
337
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
307
338
|
}
|
|
308
339
|
process.stderr.write('\n');
|
|
309
340
|
}
|
|
@@ -317,6 +348,7 @@ export default class Users extends Command {
|
|
|
317
348
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
318
349
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
319
350
|
data,
|
|
351
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
320
352
|
contextName: flags.context,
|
|
321
353
|
binary: true,
|
|
322
354
|
});
|
|
@@ -342,6 +374,7 @@ export default class Users extends Command {
|
|
|
342
374
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
343
375
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
344
376
|
data,
|
|
377
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
345
378
|
contextName: flags.context,
|
|
346
379
|
binary: true,
|
|
347
380
|
});
|
|
@@ -362,6 +395,7 @@ export default class Users extends Command {
|
|
|
362
395
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
363
396
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
364
397
|
data,
|
|
398
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
365
399
|
contextName: flags.context,
|
|
366
400
|
acceptAny: true,
|
|
367
401
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,31 +12,31 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["files"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "preview", "get", "update", "delete", "regenerate", "replace", "fields-contributions", "fields-contributions-export", "approve", "mark-as-filed", "xml", "notices-dismiss", "notices-restore", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-payments", "create-payments", "contributions-exclude", "exclusions-restore"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/vat-declarations', summary: 'List VAT reports (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/vat-declarations', summary: 'Create a VAT declaration report (always async-accepted)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'preview': { method: 'GET', path: '/v1/vat-declarations/preview', summary: 'Preview the in-scope counts and late entries for a candidate period', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'get': { method: 'GET', path: '/v1/vat-declarations/{id}', summary: 'Get a VAT report by id (this is the polling endpoint for async generation)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'update': { method: 'PATCH', path: '/v1/vat-declarations/{id}', summary: 'Update manualAdjustments, submission type, or amount basis on a DRAFT report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['manualAdjustments'] },
|
|
19
|
-
'delete': { method: 'DELETE', path: '/v1/vat-declarations/{id}', summary: 'Delete a VAT declaration that is still in DRAFT status', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'regenerate': { method: 'POST', path: '/v1/vat-declarations/{id}/regenerate', summary: 'Re-run the full generation pipeline on a DRAFT report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'replace': { method: 'POST', path: '/v1/vat-declarations/{id}/replace', summary: 'Create a corrective DRAFT (Berichtigungsabrechnung) from a FILED report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'create-files': { method: 'POST', path: '/v1/vat-declarations/{parentId}/files', summary: 'Upload a file attachment to a VAT declaration', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'get-files': { method: 'GET', path: '/v1/vat-declarations/{parentId}/files/{fileId}', summary: 'Get a file attachment for a VAT declaration', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'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: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'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, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'contributions-exclude': { method: 'POST', path: '/v1/vat-declarations/{id}/contributions/{contributionId}/exclude', summary: 'Take the booking behind one contribution row out of a DRAFT declaration.', pathParams: ['id', 'contributionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'exclusions-restore': { method: 'POST', path: '/v1/vat-declarations/{id}/exclusions/{exclusionId}/restore', summary: 'Put an excluded booking back into a DRAFT declaration.', pathParams: ['id', 'exclusionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/vat-declarations', summary: 'List VAT reports (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/vat-declarations', summary: 'Create a VAT declaration report (always async-accepted)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'preview': { method: 'GET', path: '/v1/vat-declarations/preview', summary: 'Preview the in-scope counts and late entries for a candidate period', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'get': { method: 'GET', path: '/v1/vat-declarations/{id}', summary: 'Get a VAT report by id (this is the polling endpoint for async generation)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'update': { method: 'PATCH', path: '/v1/vat-declarations/{id}', summary: 'Update manualAdjustments, submission type, or amount basis on a DRAFT report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['manualAdjustments'], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'delete': { method: 'DELETE', path: '/v1/vat-declarations/{id}', summary: 'Delete a VAT declaration that is still in DRAFT status', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'regenerate': { method: 'POST', path: '/v1/vat-declarations/{id}/regenerate', summary: 'Re-run the full generation pipeline on a DRAFT report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'replace': { method: 'POST', path: '/v1/vat-declarations/{id}/replace', summary: 'Create a corrective DRAFT (Berichtigungsabrechnung) from a FILED report', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'create-files': { method: 'POST', path: '/v1/vat-declarations/{parentId}/files', summary: 'Upload a file attachment to a VAT declaration', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'get-files': { method: 'GET', path: '/v1/vat-declarations/{parentId}/files/{fileId}', summary: 'Get a file attachment for a VAT declaration', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'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: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'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, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'contributions-exclude': { method: 'POST', path: '/v1/vat-declarations/{id}/contributions/{contributionId}/exclude', summary: 'Take the booking behind one contribution row out of a DRAFT declaration.', pathParams: ['id', 'contributionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'exclusions-restore': { method: 'POST', path: '/v1/vat-declarations/{id}/exclusions/{exclusionId}/restore', summary: 'Put an excluded booking back into a DRAFT declaration.', pathParams: ['id', 'exclusionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
40
|
};
|
|
40
41
|
export default class VatDeclarations extends Command {
|
|
41
42
|
static description = 'Manage vat declarations';
|
|
@@ -57,7 +58,7 @@ export default class VatDeclarations extends Command {
|
|
|
57
58
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
58
59
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
59
60
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
60
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
61
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
61
62
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
62
63
|
'field-id': Flags.string({ description: 'Path param: fieldId' }),
|
|
63
64
|
'notice-id': Flags.string({ description: 'Path param: noticeId' }),
|
|
@@ -193,6 +194,17 @@ export default class VatDeclarations extends Command {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
}
|
|
197
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
198
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
199
|
+
for (const param of endpoint.specParams) {
|
|
200
|
+
const value = flags[param.flag];
|
|
201
|
+
if (value === undefined || value === '') {
|
|
202
|
+
if (param.required)
|
|
203
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
queryParams[param.name] = value;
|
|
207
|
+
}
|
|
196
208
|
let data;
|
|
197
209
|
if (endpoint.isMultipart) {
|
|
198
210
|
if (!flags.file)
|
|
@@ -213,6 +225,25 @@ export default class VatDeclarations extends Command {
|
|
|
213
225
|
}
|
|
214
226
|
data = form;
|
|
215
227
|
}
|
|
228
|
+
else if (endpoint.bodyMediaType) {
|
|
229
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
230
|
+
// verbatim, under the content type the endpoint asks for.
|
|
231
|
+
if (flags.file) {
|
|
232
|
+
const fsModule = await import('node:fs');
|
|
233
|
+
try {
|
|
234
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (flags.data) {
|
|
241
|
+
data = flags.data;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
216
247
|
else if (endpoint.hasBody) {
|
|
217
248
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
218
249
|
// input file — skip the read-as-body branch.
|
|
@@ -308,7 +339,7 @@ export default class VatDeclarations extends Command {
|
|
|
308
339
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
309
340
|
}
|
|
310
341
|
else if (data) {
|
|
311
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
342
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
312
343
|
}
|
|
313
344
|
process.stderr.write('\n');
|
|
314
345
|
}
|
|
@@ -322,6 +353,7 @@ export default class VatDeclarations extends Command {
|
|
|
322
353
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
323
354
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
324
355
|
data,
|
|
356
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
325
357
|
contextName: flags.context,
|
|
326
358
|
binary: true,
|
|
327
359
|
});
|
|
@@ -347,6 +379,7 @@ export default class VatDeclarations extends Command {
|
|
|
347
379
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
348
380
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
349
381
|
data,
|
|
382
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
350
383
|
contextName: flags.context,
|
|
351
384
|
binary: true,
|
|
352
385
|
});
|
|
@@ -367,6 +400,7 @@ export default class VatDeclarations extends Command {
|
|
|
367
400
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
368
401
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
369
402
|
data,
|
|
403
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
370
404
|
contextName: flags.context,
|
|
371
405
|
acceptAny: true,
|
|
372
406
|
});
|