@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.
Files changed (85) hide show
  1. package/dist/commands/access-groups.js +42 -8
  2. package/dist/commands/account-transaction-allocations.js +38 -4
  3. package/dist/commands/account-transactions.d.ts +2 -0
  4. package/dist/commands/account-transactions.js +68 -32
  5. package/dist/commands/accounts.js +46 -12
  6. package/dist/commands/agent-platform.js +37 -3
  7. package/dist/commands/agent-runs.js +49 -15
  8. package/dist/commands/analytics.js +39 -5
  9. package/dist/commands/api-clients.js +47 -13
  10. package/dist/commands/api-keys.js +40 -6
  11. package/dist/commands/async-jobs.js +45 -11
  12. package/dist/commands/audit-log.js +38 -4
  13. package/dist/commands/bank-accounts.js +54 -20
  14. package/dist/commands/bank-integrations.js +56 -22
  15. package/dist/commands/business-partners.js +77 -43
  16. package/dist/commands/chat.js +43 -9
  17. package/dist/commands/credit-card-accounts.js +57 -23
  18. package/dist/commands/currencies.js +37 -3
  19. package/dist/commands/custody-accounts.js +41 -7
  20. package/dist/commands/dashboards.js +52 -18
  21. package/dist/commands/delivery-notes.js +69 -35
  22. package/dist/commands/document-checksums.d.ts +1 -0
  23. package/dist/commands/document-checksums.js +38 -3
  24. package/dist/commands/dunning-configs.js +41 -7
  25. package/dist/commands/dunning-reminders.js +44 -10
  26. package/dist/commands/dunning-runs.js +37 -3
  27. package/dist/commands/email-transactions.js +39 -5
  28. package/dist/commands/employees.js +77 -43
  29. package/dist/commands/entity-configurations.js +39 -5
  30. package/dist/commands/event-mapping-rules.js +37 -3
  31. package/dist/commands/event-processor-mappings.js +41 -7
  32. package/dist/commands/files.js +48 -14
  33. package/dist/commands/financial-instrument-transactions.d.ts +56 -0
  34. package/dist/commands/financial-instrument-transactions.js +1369 -0
  35. package/dist/commands/financial-instrument-types.js +41 -7
  36. package/dist/commands/financial-instruments.js +41 -7
  37. package/dist/commands/health.js +41 -7
  38. package/dist/commands/imports.js +39 -5
  39. package/dist/commands/inbox.js +42 -8
  40. package/dist/commands/integrations.js +39 -5
  41. package/dist/commands/item-categories.js +41 -7
  42. package/dist/commands/items.js +42 -8
  43. package/dist/commands/journal-lines.js +37 -3
  44. package/dist/commands/journals.js +61 -27
  45. package/dist/commands/kpis.js +44 -10
  46. package/dist/commands/ledgers.js +83 -49
  47. package/dist/commands/my-account.js +54 -20
  48. package/dist/commands/notifications.js +37 -3
  49. package/dist/commands/office-locations.js +41 -7
  50. package/dist/commands/payment-methods.js +46 -12
  51. package/dist/commands/payment-runs.js +54 -20
  52. package/dist/commands/payment-terms.js +42 -8
  53. package/dist/commands/payments.js +43 -9
  54. package/dist/commands/payroll-runs.js +71 -37
  55. package/dist/commands/permissions.js +37 -3
  56. package/dist/commands/price-lists.js +48 -14
  57. package/dist/commands/processor-mappings.js +40 -6
  58. package/dist/commands/processors.js +46 -12
  59. package/dist/commands/purchase-order-types.js +41 -7
  60. package/dist/commands/purchase-orders.js +60 -26
  61. package/dist/commands/reports.js +43 -8
  62. package/dist/commands/roles.js +40 -6
  63. package/dist/commands/salary-types.js +41 -7
  64. package/dist/commands/sales-invoices.js +85 -51
  65. package/dist/commands/sales-orders.js +69 -35
  66. package/dist/commands/saved-views.js +39 -5
  67. package/dist/commands/scheduled-processor-mappings.js +41 -7
  68. package/dist/commands/schedules.js +45 -11
  69. package/dist/commands/settings.js +38 -4
  70. package/dist/commands/tags.js +42 -8
  71. package/dist/commands/tax-codes.js +44 -10
  72. package/dist/commands/tax-matrix.js +41 -7
  73. package/dist/commands/templates.js +49 -15
  74. package/dist/commands/tenants.js +44 -10
  75. package/dist/commands/tools.js +38 -4
  76. package/dist/commands/users.js +58 -24
  77. package/dist/commands/vat-declarations.js +61 -27
  78. package/dist/commands/vendor-invoices.js +81 -47
  79. package/dist/commands/webhooks.js +43 -9
  80. package/dist/commands/work-summary.js +37 -3
  81. package/dist/lib/paths.d.ts +8 -0
  82. package/dist/lib/paths.js +16 -0
  83. package/dist/lib/production-guard.js +2 -0
  84. package/oclif.manifest.json +199 -2
  85. package/package.json +9 -3
@@ -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,18 +12,18 @@ const SERVER_IMPORTS = [];
11
12
  const NESTED_UPSERTS = [];
12
13
  const SUBCOMMANDS = [...["list", "create", "download-all", "download", "get", "references", "update", "discard", "move", "retention", "hold", "reclassify"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
13
14
  const ENDPOINTS = {
14
- 'list': { method: 'GET', path: '/v1/files', summary: 'List files (paginated, permission-scoped)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
15
- 'create': { method: 'POST', path: '/v1/files', summary: 'Upload a file (streaming, memory-efficient)', pathParams: [], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
16
- 'download-all': { method: 'GET', path: '/v1/files/download/*', summary: 'Download file directly by storage key', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
17
- 'download': { method: 'GET', path: '/v1/files/{id}/download', summary: 'Get a signed download URL for a file', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
18
- 'get': { method: 'GET', path: '/v1/files/{id}', summary: 'Get a file by id (permission-scoped)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
19
- 'references': { method: 'POST', path: '/v1/files/references', summary: 'Register a file reference to an existing storage object', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
20
- 'update': { method: 'PATCH', path: '/v1/files/{fileId}', summary: 'Update file metadata (type, parent, sortOrder)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'references'] },
21
- 'discard': { method: 'POST', path: '/v1/files/{fileId}/discard', summary: 'Discard a file (sets status DISCARDED; stays readable by id)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
22
- 'move': { method: 'POST', path: '/v1/files/{fileId}/move', summary: 'Move file between storage zones', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
23
- 'retention': { method: 'POST', path: '/v1/files/{fileId}/retention', summary: 'Set or override retention period on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
24
- 'hold': { method: 'POST', path: '/v1/files/{fileId}/hold', summary: 'Set or release legal hold on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
25
- 'reclassify': { method: 'POST', path: '/v1/files/{fileId}/reclassify', summary: 'Reclassify a file and reprocess it through the inbox pipeline', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
15
+ 'list': { method: 'GET', path: '/v1/files', summary: 'List files (paginated, permission-scoped)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
16
+ 'create': { method: 'POST', path: '/v1/files', summary: 'Upload a file (streaming, memory-efficient)', pathParams: [], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
17
+ 'download-all': { method: 'GET', path: '/v1/files/download/*', summary: 'Download file directly by storage key', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
18
+ 'download': { method: 'GET', path: '/v1/files/{id}/download', summary: 'Get a signed download URL for a file', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
19
+ 'get': { method: 'GET', path: '/v1/files/{id}', summary: 'Get a file by id (permission-scoped)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
20
+ 'references': { method: 'POST', path: '/v1/files/references', summary: 'Register a file reference to an existing storage object', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
21
+ 'update': { method: 'PATCH', path: '/v1/files/{fileId}', summary: 'Update file metadata (type, parent, sortOrder)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['tagIds', 'tagCodes', 'references'], bodyMediaType: '', specParams: [] },
22
+ 'discard': { method: 'POST', path: '/v1/files/{fileId}/discard', summary: 'Discard a file (sets status DISCARDED; stays readable by id)', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
23
+ 'move': { method: 'POST', path: '/v1/files/{fileId}/move', summary: 'Move file between storage zones', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
24
+ 'retention': { method: 'POST', path: '/v1/files/{fileId}/retention', summary: 'Set or override retention period on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
25
+ 'hold': { method: 'POST', path: '/v1/files/{fileId}/hold', summary: 'Set or release legal hold on a file', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
26
+ 'reclassify': { method: 'POST', path: '/v1/files/{fileId}/reclassify', summary: 'Reclassify a file and reprocess it through the inbox pipeline', pathParams: ['fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
26
27
  };
27
28
  export default class Files extends Command {
28
29
  static description = 'Manage files';
@@ -44,7 +45,7 @@ export default class Files extends Command {
44
45
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
45
46
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
46
47
  data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
47
- file: Flags.string({ char: 'f', description: 'Read request body from file' }),
48
+ file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
48
49
  set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
49
50
  page: Flags.string({ description: 'Page number' }),
50
51
  limit: Flags.string({ description: 'Items per page' }),
@@ -175,6 +176,17 @@ export default class Files extends Command {
175
176
  }
176
177
  }
177
178
  }
179
+ // Flags generated from this endpoint's own parameters. Raw-body endpoints
180
+ // have them: their body is not JSON, so --set cannot carry a value there.
181
+ for (const param of endpoint.specParams) {
182
+ const value = flags[param.flag];
183
+ if (value === undefined || value === '') {
184
+ if (param.required)
185
+ this.error(`Missing required flag: --${param.flag}`);
186
+ continue;
187
+ }
188
+ queryParams[param.name] = value;
189
+ }
178
190
  let data;
179
191
  if (endpoint.isMultipart) {
180
192
  if (!flags.file)
@@ -195,6 +207,25 @@ export default class Files extends Command {
195
207
  }
196
208
  data = form;
197
209
  }
210
+ else if (endpoint.bodyMediaType) {
211
+ // The body is not JSON (today only application/x-ndjson): it is sent
212
+ // verbatim, under the content type the endpoint asks for.
213
+ if (flags.file) {
214
+ const fsModule = await import('node:fs');
215
+ try {
216
+ data = fsModule.readFileSync(flags.file, 'utf-8');
217
+ }
218
+ catch {
219
+ this.error(`Failed to read file: ${flags.file}`);
220
+ }
221
+ }
222
+ else if (flags.data) {
223
+ data = flags.data;
224
+ }
225
+ else {
226
+ this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
227
+ }
228
+ }
198
229
  else if (endpoint.hasBody) {
199
230
  // For binary-response endpoints, --file is the output path, not a JSON
200
231
  // input file — skip the read-as-body branch.
@@ -290,7 +321,7 @@ export default class Files extends Command {
290
321
  process.stderr.write(`Body: [multipart/form-data file upload]\n`);
291
322
  }
292
323
  else if (data) {
293
- process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
324
+ process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
294
325
  }
295
326
  process.stderr.write('\n');
296
327
  }
@@ -304,6 +335,7 @@ export default class Files extends Command {
304
335
  const binResponse = await apiRequest(endpoint.method, apiPath, {
305
336
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
306
337
  data,
338
+ contentType: endpoint.bodyMediaType || undefined,
307
339
  contextName: flags.context,
308
340
  binary: true,
309
341
  });
@@ -329,6 +361,7 @@ export default class Files extends Command {
329
361
  const raw = await apiRequest(endpoint.method, apiPath, {
330
362
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
331
363
  data,
364
+ contentType: endpoint.bodyMediaType || undefined,
332
365
  contextName: flags.context,
333
366
  binary: true,
334
367
  });
@@ -349,6 +382,7 @@ export default class Files extends Command {
349
382
  response = await apiRequest(endpoint.method, apiPath, {
350
383
  params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
351
384
  data,
385
+ contentType: endpoint.bodyMediaType || undefined,
352
386
  contextName: flags.context,
353
387
  acceptAny: true,
354
388
  });
@@ -0,0 +1,56 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class FinancialInstrumentTransactions extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ action: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ context: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ table: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ csv: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ data: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ set: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
+ include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
+ search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
21
+ 'sort-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
+ filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
+ query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
+ fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
+ sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
+ meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
27
+ 'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
+ };
29
+ run(): Promise<void>;
30
+ private runUpsert;
31
+ /**
32
+ * The API's own import: the whole array goes up in one request and comes
33
+ * back as an import run, which records what happened to every record. A bad
34
+ * record lands in errorLog and the rest are still applied, and the run stays
35
+ * readable afterwards with: aderis imports get <id>.
36
+ */
37
+ private runServerImport;
38
+ /** Renders an import run: its counts, then whatever the server refused. */
39
+ private printImportRun;
40
+ private runExport;
41
+ private runCamt053Import;
42
+ private runNestedUpsert;
43
+ private parseFilterValue;
44
+ /** The page line under a table: which page, how many, and any sums the API returned. */
45
+ private printPageSummary;
46
+ /**
47
+ * The API caps how many records a page may hold. Asking for more and getting
48
+ * fewer looks like "that is everything" unless it is said out loud.
49
+ */
50
+ private warnShortPage;
51
+ private sanitizeOutput;
52
+ private getColumns;
53
+ private getValue;
54
+ private printTable;
55
+ private printCsv;
56
+ }