@aderis-erp/cli 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/commands/access-groups.js +42 -8
- package/dist/commands/account-transaction-allocations.js +38 -4
- package/dist/commands/account-transactions.d.ts +2 -0
- package/dist/commands/account-transactions.js +68 -32
- package/dist/commands/accounts.js +46 -12
- package/dist/commands/agent-platform.js +37 -3
- package/dist/commands/agent-runs.js +49 -15
- package/dist/commands/analytics.js +39 -5
- package/dist/commands/api-clients.d.ts +58 -0
- package/dist/commands/api-clients.js +1375 -0
- package/dist/commands/api-keys.js +40 -6
- package/dist/commands/async-jobs.js +45 -11
- package/dist/commands/audit-log.js +38 -4
- package/dist/commands/bank-accounts.js +54 -20
- package/dist/commands/bank-integrations.js +56 -22
- package/dist/commands/business-partners.js +77 -43
- package/dist/commands/chat.js +43 -9
- package/dist/commands/credit-card-accounts.d.ts +4 -0
- package/dist/commands/credit-card-accounts.js +64 -25
- package/dist/commands/currencies.d.ts +56 -0
- package/dist/commands/currencies.js +1361 -0
- package/dist/commands/custody-accounts.d.ts +56 -0
- package/dist/commands/custody-accounts.js +1369 -0
- package/dist/commands/{integration-identities.d.ts → dashboards.d.ts} +3 -3
- package/dist/commands/dashboards.js +1381 -0
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +57 -0
- package/dist/commands/{integration-identities.js → document-checksums.js} +48 -21
- package/dist/commands/dunning-configs.js +41 -7
- package/dist/commands/dunning-reminders.js +44 -10
- package/dist/commands/dunning-runs.js +37 -3
- package/dist/commands/email-transactions.js +39 -5
- package/dist/commands/employees.js +77 -43
- package/dist/commands/entity-configurations.js +39 -5
- package/dist/commands/event-mapping-rules.js +37 -3
- package/dist/commands/event-processor-mappings.js +41 -7
- package/dist/commands/files.js +48 -14
- package/dist/commands/financial-instrument-transactions.d.ts +56 -0
- package/dist/commands/financial-instrument-transactions.js +1369 -0
- package/dist/commands/financial-instrument-types.d.ts +56 -0
- package/dist/commands/financial-instrument-types.js +1369 -0
- package/dist/commands/financial-instruments.d.ts +56 -0
- package/dist/commands/financial-instruments.js +1369 -0
- package/dist/commands/health.js +41 -7
- package/dist/commands/imports.js +39 -5
- package/dist/commands/inbox.js +42 -8
- package/dist/commands/integrations.js +39 -5
- package/dist/commands/item-categories.js +41 -7
- package/dist/commands/items.js +42 -8
- package/dist/commands/journal-lines.js +37 -3
- package/dist/commands/journals.js +61 -27
- package/dist/commands/{workflows.d.ts → kpis.d.ts} +1 -1
- package/dist/commands/kpis.js +1371 -0
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.d.ts +56 -0
- package/dist/commands/notifications.js +1360 -0
- package/dist/commands/office-locations.js +41 -7
- package/dist/commands/payment-methods.js +46 -12
- package/dist/commands/payment-runs.js +54 -20
- package/dist/commands/payment-terms.js +42 -8
- package/dist/commands/payments.js +43 -9
- package/dist/commands/payroll-runs.js +71 -37
- package/dist/commands/permissions.js +37 -3
- package/dist/commands/price-lists.js +48 -14
- package/dist/commands/processor-mappings.js +40 -6
- package/dist/commands/processors.js +46 -12
- package/dist/commands/purchase-order-types.js +41 -7
- package/dist/commands/purchase-orders.js +60 -26
- package/dist/commands/reports.js +43 -8
- package/dist/commands/roles.js +40 -6
- package/dist/commands/salary-types.js +41 -7
- package/dist/commands/sales-invoices.js +85 -51
- package/dist/commands/sales-orders.js +69 -35
- package/dist/commands/saved-views.js +39 -5
- package/dist/commands/scheduled-processor-mappings.js +41 -7
- package/dist/commands/schedules.js +45 -11
- package/dist/commands/settings.d.ts +56 -0
- package/dist/commands/settings.js +1361 -0
- package/dist/commands/tags.js +42 -8
- package/dist/commands/tax-codes.js +44 -10
- package/dist/commands/tax-matrix.js +41 -7
- package/dist/commands/templates.js +50 -15
- package/dist/commands/tenants.js +44 -10
- package/dist/commands/tools.js +38 -4
- package/dist/commands/users.js +58 -24
- package/dist/commands/vat-declarations.js +61 -27
- package/dist/commands/vendor-invoices.js +82 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.d.ts +56 -0
- package/dist/commands/{workflows.js → work-summary.js} +49 -18
- package/dist/lib/auth/index.js +5 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.d.ts +42 -0
- package/dist/lib/production-guard.js +94 -0
- package/oclif.manifest.json +2142 -333
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Command-line interface for Aderis Finance ERP. Manage your Aderis account, execu
|
|
|
8
8
|
- **Multi-Environment Support** - Switch between dev, test, staging and production environments
|
|
9
9
|
- **Multi-Client Support** - Manage multiple clients with named contexts
|
|
10
10
|
- **Multi-Tenant Support** - Switch between tenants within a single login
|
|
11
|
+
- **Production Guard for Claude Code** - From an `@aderis.com` address, only a Claude account in the Aderis organisation can reach `live`
|
|
11
12
|
- **Full API Access** - Execute all Aderis API endpoints from the command line
|
|
12
13
|
- **Auto-Generated Commands** - Commands generated directly from OpenAPI spec
|
|
13
14
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,12 +12,12 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "list-summaries", "get", "update", "delete"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/access-groups', summary: 'List access groups (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/access-groups', summary: 'Create a new access group', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
|
|
16
|
-
'list-summaries': { method: 'GET', path: '/v1/access-groups/summaries', summary: 'List access groups without members (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'get': { method: 'GET', path: '/v1/access-groups/{id}', summary: 'Get a single access group by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'update': { method: 'PATCH', path: '/v1/access-groups/{id}', summary: 'Update an existing access group', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'] },
|
|
19
|
-
'delete': { method: 'DELETE', path: '/v1/access-groups/{id}', summary: 'Delete an access group', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/access-groups', summary: 'List access groups (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/access-groups', summary: 'Create a new access group', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'list-summaries': { method: 'GET', path: '/v1/access-groups/summaries', summary: 'List access groups without members (paginated)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'get': { method: 'GET', path: '/v1/access-groups/{id}', summary: 'Get a single access group by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'update': { method: 'PATCH', path: '/v1/access-groups/{id}', summary: 'Update an existing access group', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['types', 'userIds'], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'delete': { method: 'DELETE', path: '/v1/access-groups/{id}', summary: 'Delete an access group', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
21
|
};
|
|
21
22
|
export default class AccessGroups extends Command {
|
|
22
23
|
static description = 'Manage access groups';
|
|
@@ -38,7 +39,7 @@ export default class AccessGroups extends Command {
|
|
|
38
39
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
39
40
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
40
41
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
41
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
42
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
42
43
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
43
44
|
page: Flags.string({ description: 'Page number' }),
|
|
44
45
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -169,6 +170,17 @@ export default class AccessGroups extends Command {
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
}
|
|
173
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
174
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
175
|
+
for (const param of endpoint.specParams) {
|
|
176
|
+
const value = flags[param.flag];
|
|
177
|
+
if (value === undefined || value === '') {
|
|
178
|
+
if (param.required)
|
|
179
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
queryParams[param.name] = value;
|
|
183
|
+
}
|
|
172
184
|
let data;
|
|
173
185
|
if (endpoint.isMultipart) {
|
|
174
186
|
if (!flags.file)
|
|
@@ -189,6 +201,25 @@ export default class AccessGroups extends Command {
|
|
|
189
201
|
}
|
|
190
202
|
data = form;
|
|
191
203
|
}
|
|
204
|
+
else if (endpoint.bodyMediaType) {
|
|
205
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
206
|
+
// verbatim, under the content type the endpoint asks for.
|
|
207
|
+
if (flags.file) {
|
|
208
|
+
const fsModule = await import('node:fs');
|
|
209
|
+
try {
|
|
210
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (flags.data) {
|
|
217
|
+
data = flags.data;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
192
223
|
else if (endpoint.hasBody) {
|
|
193
224
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
194
225
|
// input file — skip the read-as-body branch.
|
|
@@ -284,7 +315,7 @@ export default class AccessGroups extends Command {
|
|
|
284
315
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
285
316
|
}
|
|
286
317
|
else if (data) {
|
|
287
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
318
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
288
319
|
}
|
|
289
320
|
process.stderr.write('\n');
|
|
290
321
|
}
|
|
@@ -298,6 +329,7 @@ export default class AccessGroups extends Command {
|
|
|
298
329
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
299
330
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
300
331
|
data,
|
|
332
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
301
333
|
contextName: flags.context,
|
|
302
334
|
binary: true,
|
|
303
335
|
});
|
|
@@ -323,6 +355,7 @@ export default class AccessGroups extends Command {
|
|
|
323
355
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
324
356
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
325
357
|
data,
|
|
358
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
326
359
|
contextName: flags.context,
|
|
327
360
|
binary: true,
|
|
328
361
|
});
|
|
@@ -343,6 +376,7 @@ export default class AccessGroups extends Command {
|
|
|
343
376
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
344
377
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
345
378
|
data,
|
|
379
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
346
380
|
contextName: flags.context,
|
|
347
381
|
acceptAny: true,
|
|
348
382
|
});
|
|
@@ -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", "get"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/account-transaction-allocations', summary: 'List account transaction allocations with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'get': { method: 'GET', path: '/v1/account-transaction-allocations/{id}', summary: 'Get an account transaction allocation by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/account-transaction-allocations', summary: 'List account transaction allocations with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'get': { method: 'GET', path: '/v1/account-transaction-allocations/{id}', summary: 'Get an account transaction allocation by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
17
|
};
|
|
17
18
|
export default class AccountTransactionAllocations extends Command {
|
|
18
19
|
static description = 'Manage account transaction allocations';
|
|
@@ -31,7 +32,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
31
32
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
32
33
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
33
34
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
34
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
35
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
35
36
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
36
37
|
page: Flags.string({ description: 'Page number' }),
|
|
37
38
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -162,6 +163,17 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
}
|
|
166
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
167
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
168
|
+
for (const param of endpoint.specParams) {
|
|
169
|
+
const value = flags[param.flag];
|
|
170
|
+
if (value === undefined || value === '') {
|
|
171
|
+
if (param.required)
|
|
172
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
queryParams[param.name] = value;
|
|
176
|
+
}
|
|
165
177
|
let data;
|
|
166
178
|
if (endpoint.isMultipart) {
|
|
167
179
|
if (!flags.file)
|
|
@@ -182,6 +194,25 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
182
194
|
}
|
|
183
195
|
data = form;
|
|
184
196
|
}
|
|
197
|
+
else if (endpoint.bodyMediaType) {
|
|
198
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
199
|
+
// verbatim, under the content type the endpoint asks for.
|
|
200
|
+
if (flags.file) {
|
|
201
|
+
const fsModule = await import('node:fs');
|
|
202
|
+
try {
|
|
203
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (flags.data) {
|
|
210
|
+
data = flags.data;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
185
216
|
else if (endpoint.hasBody) {
|
|
186
217
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
187
218
|
// input file — skip the read-as-body branch.
|
|
@@ -277,7 +308,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
277
308
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
278
309
|
}
|
|
279
310
|
else if (data) {
|
|
280
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
311
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
281
312
|
}
|
|
282
313
|
process.stderr.write('\n');
|
|
283
314
|
}
|
|
@@ -291,6 +322,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
291
322
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
292
323
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
293
324
|
data,
|
|
325
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
294
326
|
contextName: flags.context,
|
|
295
327
|
binary: true,
|
|
296
328
|
});
|
|
@@ -316,6 +348,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
316
348
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
317
349
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
318
350
|
data,
|
|
351
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
319
352
|
contextName: flags.context,
|
|
320
353
|
binary: true,
|
|
321
354
|
});
|
|
@@ -336,6 +369,7 @@ export default class AccountTransactionAllocations extends Command {
|
|
|
336
369
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
337
370
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
338
371
|
data,
|
|
372
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
339
373
|
contextName: flags.context,
|
|
340
374
|
acceptAny: true,
|
|
341
375
|
});
|
|
@@ -14,6 +14,8 @@ export default class AccountTransactions extends Command {
|
|
|
14
14
|
data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
15
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
16
|
set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'tenant-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
archive: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
19
|
mode: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
20
|
reference: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
21
|
async: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
@@ -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,36 +12,36 @@ const SERVER_IMPORTS = ["import"];
|
|
|
11
12
|
const NESTED_UPSERTS = ["allocations", "allocations-notes", "notes"];
|
|
12
13
|
const SUBCOMMANDS = [...["retry-booking", "recover-booking", "list", "create", "status-counts", "get", "update", "delete", "reconcile", "allocations-reprocess-unbooked", "allocations-unbooked", "list-allocations", "create-allocations", "get-allocations", "update-allocations", "delete-allocations", "list-allocations-settlement-accounts", "allocations-confirm", "import", "import-camt053", "list-allocations-notes", "create-allocations-notes", "get-allocations-notes", "update-allocations-notes", "delete-allocations-notes", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'retry-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/retry-booking', summary: 'Retry complete booking of an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
15
|
-
'recover-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/recover-booking', summary: 'Verify existing accounting and book missing entries together', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
16
|
-
'list': { method: 'GET', path: '/v1/account-transactions', summary: 'Get all account transactions with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'create': { method: 'POST', path: '/v1/account-transactions', summary: 'Create a new account transaction', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
18
|
-
'status-counts': { method: 'GET', path: '/v1/account-transactions/status-counts', summary: 'Count account transactions per reconciliation status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'get': { method: 'GET', path: '/v1/account-transactions/{id}', summary: 'Get an account transaction by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'update': { method: 'PATCH', path: '/v1/account-transactions/{id}', summary: 'Update an account transaction', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'] },
|
|
21
|
-
'delete': { method: 'DELETE', path: '/v1/account-transactions/{id}', summary: 'Delete an account transaction', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'reconcile': { method: 'POST', path: '/v1/account-transactions/reconcile', summary: 'Send selected transactions to the reconciliation agent', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['transactionIds'] },
|
|
23
|
-
'allocations-reprocess-unbooked': { method: 'POST', path: '/v1/account-transactions/allocations/reprocess-unbooked', summary: 'Internal — re-book or repair allocations stuck at CONFIRMED', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocationIds'] },
|
|
24
|
-
'allocations-unbooked': { method: 'GET', path: '/v1/account-transactions/allocations/unbooked', summary: 'Internal — list allocations stuck at CONFIRMED', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'list-allocations': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations', summary: 'Get all allocations for an account transaction', pathParams: ['transactionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'create-allocations': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations', summary: 'Create an allocation for an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes'] },
|
|
27
|
-
'get-allocations': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Get an allocation by ID', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'update-allocations': { method: 'PATCH', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Update an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes'] },
|
|
29
|
-
'delete-allocations': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Delete an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'list-allocations-settlement-accounts': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/settlement-accounts', summary: 'Which account each ledger would settle the allocated document against', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'allocations-confirm': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/confirm', summary: 'Confirm an allocation (transition from REVIEW to CONFIRMED)', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['counterAccounts'] },
|
|
32
|
-
'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import account transactions', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'import-camt053': { method: 'POST', path: '/v1/account-transactions/import/camt053', summary: 'Import CAMT.053 bank statement (ISO 20022 format)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'list-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Get all notes for an allocation', pathParams: ['allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'create-allocations-notes': { method: 'POST', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Create a note for an allocation', pathParams: ['allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'get-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Get a specific note for an allocation', pathParams: ['allocationId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'update-allocations-notes': { method: 'PATCH', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Update a note for an allocation', pathParams: ['allocationId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'delete-allocations-notes': { method: 'DELETE', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Delete a note from an allocation', pathParams: ['allocationId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
-
'list-notes': { method: 'GET', path: '/v1/account-transactions/{transactionId}/notes', summary: 'Get all notes for an account transaction', pathParams: ['transactionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
-
'create-notes': { method: 'POST', path: '/v1/account-transactions/{transactionId}/notes', summary: 'Create a note for an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
-
'get-notes': { method: 'GET', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Get a specific note for an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
-
'update-notes': { method: 'PATCH', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Update a note for an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
43
|
-
'delete-notes': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Delete a note from an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'retry-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/retry-booking', summary: 'Retry complete booking of an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'recover-booking': { method: 'POST', path: '/v1/account-transactions/{transactionId}/recover-booking', summary: 'Verify existing accounting and book missing entries together', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'list': { method: 'GET', path: '/v1/account-transactions', summary: 'Get all account transactions with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'create': { method: 'POST', path: '/v1/account-transactions', summary: 'Create a new account transaction', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'status-counts': { method: 'GET', path: '/v1/account-transactions/status-counts', summary: 'Count account transactions per reconciliation status', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'get': { method: 'GET', path: '/v1/account-transactions/{id}', summary: 'Get an account transaction by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'update': { method: 'PATCH', path: '/v1/account-transactions/{id}', summary: 'Update an account transaction', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocations'], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'delete': { method: 'DELETE', path: '/v1/account-transactions/{id}', summary: 'Delete an account transaction', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'reconcile': { method: 'POST', path: '/v1/account-transactions/reconcile', summary: 'Send selected transactions to the reconciliation agent', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['transactionIds'], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'allocations-reprocess-unbooked': { method: 'POST', path: '/v1/account-transactions/allocations/reprocess-unbooked', summary: 'Internal — re-book or repair allocations stuck at CONFIRMED', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['allocationIds'], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'allocations-unbooked': { method: 'GET', path: '/v1/account-transactions/allocations/unbooked', summary: 'Internal — list allocations stuck at CONFIRMED', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'list-allocations': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations', summary: 'Get all allocations for an account transaction', pathParams: ['transactionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'create-allocations': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations', summary: 'Create an allocation for an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes'], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'get-allocations': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Get an allocation by ID', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'update-allocations': { method: 'PATCH', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Update an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes'], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'delete-allocations': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}', summary: 'Delete an allocation', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'list-allocations-settlement-accounts': { method: 'GET', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/settlement-accounts', summary: 'Which account each ledger would settle the allocated document against', pathParams: ['transactionId', 'allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'allocations-confirm': { method: 'POST', path: '/v1/account-transactions/{transactionId}/allocations/{allocationId}/confirm', summary: 'Confirm an allocation (transition from REVIEW to CONFIRMED)', pathParams: ['transactionId', 'allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['counterAccounts'], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'import': { method: 'POST', path: '/v1/account-transactions/import', summary: 'Import account transactions', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'import-camt053': { method: 'POST', path: '/v1/account-transactions/import/camt053', summary: 'Import CAMT.053 bank statement (ISO 20022 format)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: 'application/xml', specParams: [{ "flag": "tenant-id", "name": "tenantId", "required": false }, { "flag": "archive", "name": "archive", "required": false }] },
|
|
35
|
+
'list-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Get all notes for an allocation', pathParams: ['allocationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'create-allocations-notes': { method: 'POST', path: '/v1/account-transactions/allocations/{allocationId}/notes', summary: 'Create a note for an allocation', pathParams: ['allocationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'get-allocations-notes': { method: 'GET', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Get a specific note for an allocation', pathParams: ['allocationId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'update-allocations-notes': { method: 'PATCH', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Update a note for an allocation', pathParams: ['allocationId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'delete-allocations-notes': { method: 'DELETE', path: '/v1/account-transactions/allocations/{allocationId}/notes/{noteId}', summary: 'Delete a note from an allocation', pathParams: ['allocationId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
40
|
+
'list-notes': { method: 'GET', path: '/v1/account-transactions/{transactionId}/notes', summary: 'Get all notes for an account transaction', pathParams: ['transactionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
41
|
+
'create-notes': { method: 'POST', path: '/v1/account-transactions/{transactionId}/notes', summary: 'Create a note for an account transaction', pathParams: ['transactionId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
42
|
+
'get-notes': { method: 'GET', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Get a specific note for an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
43
|
+
'update-notes': { method: 'PATCH', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Update a note for an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
44
|
+
'delete-notes': { method: 'DELETE', path: '/v1/account-transactions/{transactionId}/notes/{noteId}', summary: 'Delete a note from an account transaction', pathParams: ['transactionId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
44
45
|
};
|
|
45
46
|
export default class AccountTransactions extends Command {
|
|
46
47
|
static description = 'Manage account transactions';
|
|
@@ -62,8 +63,10 @@ export default class AccountTransactions extends Command {
|
|
|
62
63
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
63
64
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
64
65
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
65
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
66
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
66
67
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
68
|
+
'tenant-id': Flags.string({ description: 'Accepted for backward compatibility; the tenant comes from the caller identity.' }),
|
|
69
|
+
'archive': Flags.string({ description: 'Set to false to import without storing the raw XML. Absent means the raw statement is stored.' }),
|
|
67
70
|
mode: Flags.string({ description: 'Import mode: upsert (default) creates, updates or skips each record; create refuses records that already exist; update refuses records that do not', options: ['upsert', 'create', 'update'] }),
|
|
68
71
|
reference: Flags.string({ description: 'Caller-defined text stored on the import run, for tracking and filtering' }),
|
|
69
72
|
async: Flags.boolean({ description: 'Import in the background: answers with a PENDING run to follow via "aderis imports get <id>"' }),
|
|
@@ -199,6 +202,17 @@ export default class AccountTransactions extends Command {
|
|
|
199
202
|
}
|
|
200
203
|
}
|
|
201
204
|
}
|
|
205
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
206
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
207
|
+
for (const param of endpoint.specParams) {
|
|
208
|
+
const value = flags[param.flag];
|
|
209
|
+
if (value === undefined || value === '') {
|
|
210
|
+
if (param.required)
|
|
211
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
queryParams[param.name] = value;
|
|
215
|
+
}
|
|
202
216
|
let data;
|
|
203
217
|
if (endpoint.isMultipart) {
|
|
204
218
|
if (!flags.file)
|
|
@@ -219,6 +233,25 @@ export default class AccountTransactions extends Command {
|
|
|
219
233
|
}
|
|
220
234
|
data = form;
|
|
221
235
|
}
|
|
236
|
+
else if (endpoint.bodyMediaType) {
|
|
237
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
238
|
+
// verbatim, under the content type the endpoint asks for.
|
|
239
|
+
if (flags.file) {
|
|
240
|
+
const fsModule = await import('node:fs');
|
|
241
|
+
try {
|
|
242
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else if (flags.data) {
|
|
249
|
+
data = flags.data;
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
222
255
|
else if (endpoint.hasBody) {
|
|
223
256
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
224
257
|
// input file — skip the read-as-body branch.
|
|
@@ -314,7 +347,7 @@ export default class AccountTransactions extends Command {
|
|
|
314
347
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
315
348
|
}
|
|
316
349
|
else if (data) {
|
|
317
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
350
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
318
351
|
}
|
|
319
352
|
process.stderr.write('\n');
|
|
320
353
|
}
|
|
@@ -328,6 +361,7 @@ export default class AccountTransactions extends Command {
|
|
|
328
361
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
329
362
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
330
363
|
data,
|
|
364
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
331
365
|
contextName: flags.context,
|
|
332
366
|
binary: true,
|
|
333
367
|
});
|
|
@@ -353,6 +387,7 @@ export default class AccountTransactions extends Command {
|
|
|
353
387
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
354
388
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
355
389
|
data,
|
|
390
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
356
391
|
contextName: flags.context,
|
|
357
392
|
binary: true,
|
|
358
393
|
});
|
|
@@ -373,6 +408,7 @@ export default class AccountTransactions extends Command {
|
|
|
373
408
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
374
409
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
375
410
|
data,
|
|
411
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
376
412
|
contextName: flags.context,
|
|
377
413
|
acceptAny: true,
|
|
378
414
|
});
|
|
@@ -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,16 +12,16 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["notes"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/accounts', summary: 'List all accounts', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/accounts', summary: 'Create a new account', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'notes'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/accounts/{id}', summary: 'Get an account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/accounts/{id}', summary: 'Update an account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/accounts/{id}', summary: 'Delete an account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'list-notes': { method: 'GET', path: '/v1/accounts/{accountId}/notes', summary: 'Get all notes for an account', pathParams: ['accountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'create-notes': { method: 'POST', path: '/v1/accounts/{accountId}/notes', summary: 'Create a note for an account', pathParams: ['accountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'get-notes': { method: 'GET', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Get a specific note for an account', pathParams: ['accountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'update-notes': { method: 'PATCH', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Update a note for an account', pathParams: ['accountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'delete-notes': { method: 'DELETE', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Delete a note from an account', pathParams: ['accountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/accounts', summary: 'List all accounts', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/accounts', summary: 'Create a new account', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'notes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/accounts/{id}', summary: 'Get an account by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/accounts/{id}', summary: 'Update an account', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/accounts/{id}', summary: 'Delete an account', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'list-notes': { method: 'GET', path: '/v1/accounts/{accountId}/notes', summary: 'Get all notes for an account', pathParams: ['accountId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'create-notes': { method: 'POST', path: '/v1/accounts/{accountId}/notes', summary: 'Create a note for an account', pathParams: ['accountId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'get-notes': { method: 'GET', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Get a specific note for an account', pathParams: ['accountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'update-notes': { method: 'PATCH', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Update a note for an account', pathParams: ['accountId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'delete-notes': { method: 'DELETE', path: '/v1/accounts/{accountId}/notes/{noteId}', summary: 'Delete a note from an account', pathParams: ['accountId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
25
|
};
|
|
25
26
|
export default class Accounts extends Command {
|
|
26
27
|
static description = 'Manage accounts';
|
|
@@ -42,7 +43,7 @@ export default class Accounts extends Command {
|
|
|
42
43
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
43
44
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
44
45
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
45
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
46
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
46
47
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
47
48
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
48
49
|
page: Flags.string({ description: 'Page number' }),
|
|
@@ -174,6 +175,17 @@ export default class Accounts extends Command {
|
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
}
|
|
178
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
179
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
180
|
+
for (const param of endpoint.specParams) {
|
|
181
|
+
const value = flags[param.flag];
|
|
182
|
+
if (value === undefined || value === '') {
|
|
183
|
+
if (param.required)
|
|
184
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
queryParams[param.name] = value;
|
|
188
|
+
}
|
|
177
189
|
let data;
|
|
178
190
|
if (endpoint.isMultipart) {
|
|
179
191
|
if (!flags.file)
|
|
@@ -194,6 +206,25 @@ export default class Accounts extends Command {
|
|
|
194
206
|
}
|
|
195
207
|
data = form;
|
|
196
208
|
}
|
|
209
|
+
else if (endpoint.bodyMediaType) {
|
|
210
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
211
|
+
// verbatim, under the content type the endpoint asks for.
|
|
212
|
+
if (flags.file) {
|
|
213
|
+
const fsModule = await import('node:fs');
|
|
214
|
+
try {
|
|
215
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (flags.data) {
|
|
222
|
+
data = flags.data;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
197
228
|
else if (endpoint.hasBody) {
|
|
198
229
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
199
230
|
// input file — skip the read-as-body branch.
|
|
@@ -289,7 +320,7 @@ export default class Accounts extends Command {
|
|
|
289
320
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
290
321
|
}
|
|
291
322
|
else if (data) {
|
|
292
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
323
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
293
324
|
}
|
|
294
325
|
process.stderr.write('\n');
|
|
295
326
|
}
|
|
@@ -303,6 +334,7 @@ export default class Accounts extends Command {
|
|
|
303
334
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
304
335
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
305
336
|
data,
|
|
337
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
306
338
|
contextName: flags.context,
|
|
307
339
|
binary: true,
|
|
308
340
|
});
|
|
@@ -328,6 +360,7 @@ export default class Accounts extends Command {
|
|
|
328
360
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
329
361
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
330
362
|
data,
|
|
363
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
331
364
|
contextName: flags.context,
|
|
332
365
|
binary: true,
|
|
333
366
|
});
|
|
@@ -348,6 +381,7 @@ export default class Accounts extends Command {
|
|
|
348
381
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
349
382
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
350
383
|
data,
|
|
384
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
351
385
|
contextName: flags.context,
|
|
352
386
|
acceptAny: true,
|
|
353
387
|
});
|