@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
|
@@ -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,39 +12,39 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["line-items", "notes", "files"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "create-from-orders", "create-from-invoice", "create-invoice", "get", "update", "delete", "get-pdf", "create-pdf", "submit", "approve", "cancel", "replace", "copy", "deliver", "ship", "send", "create-line-items", "update-line-items-reorder", "update-line-items", "delete-line-items", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/delivery-notes', summary: 'Get all delivery notes with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/delivery-notes', summary: 'Create a new delivery note', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['files', 'notes', 'tagIds', 'tagCodes', 'lineItems'] },
|
|
16
|
-
'create-from-orders': { method: 'POST', path: '/v1/delivery-notes/create-from-orders', summary: 'Create a DRAFT delivery note from several sales orders', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderIds'] },
|
|
17
|
-
'create-from-invoice': { method: 'POST', path: '/v1/delivery-notes/create-from-invoice', summary: 'Create a DRAFT delivery note from a sales invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'create-invoice': { method: 'POST', path: '/v1/delivery-notes/create-invoice', summary: 'Create ONE draft sales invoice from several delivery notes (same customer)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['deliveryNoteIds'] },
|
|
19
|
-
'get': { method: 'GET', path: '/v1/delivery-notes/{id}', summary: 'Get a delivery note by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'update': { method: 'PATCH', path: '/v1/delivery-notes/{id}', summary: 'Update a delivery note', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['files', 'notes', 'tagIds', 'tagCodes', 'removeFileIds'] },
|
|
21
|
-
'delete': { method: 'DELETE', path: '/v1/delivery-notes/{id}', summary: 'Delete a delivery note', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'get-pdf': { method: 'GET', path: '/v1/delivery-notes/{id}/pdf', summary: 'Render a delivery note PDF as the mapped event would, or preview a stored template', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'create-pdf': { method: 'POST', path: '/v1/delivery-notes/{id}/pdf', summary: 'Render a delivery note PDF from unsaved HTML posted in the body', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'submit': { method: 'POST', path: '/v1/delivery-notes/{id}/submit', summary: 'Submit a delivery note for approval (DRAFT → PENDING_APPROVAL)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'approve': { method: 'POST', path: '/v1/delivery-notes/{id}/approve', summary: 'Approve a delivery note (DRAFT or PENDING_APPROVAL → APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'cancel': { method: 'POST', path: '/v1/delivery-notes/{id}/cancel', summary: 'Cancel a delivery note (DRAFT / PENDING_APPROVAL / APPROVED / SHIPPED / DELIVERED → CANCELLED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'replace': { method: 'POST', path: '/v1/delivery-notes/{id}/replace', summary: 'Replace a delivery note (APPROVED / SHIPPED / DELIVERED / CANCELLED → REPLACED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'copy': { method: 'POST', path: '/v1/delivery-notes/{id}/copy', summary: 'Create a copy of a delivery note as a new draft', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'deliver': { method: 'POST', path: '/v1/delivery-notes/{id}/deliver', summary: 'Mark a delivery note as delivered (SHIPPED → DELIVERED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'ship': { method: 'POST', path: '/v1/delivery-notes/{id}/ship', summary: 'Ship a delivery note (APPROVED → SHIPPED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lineItems'] },
|
|
31
|
-
'send': { method: 'POST', path: '/v1/delivery-notes/{id}/send', summary: 'Send a delivery note to its recipient by email', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['emailCc', 'emailBcc'] },
|
|
32
|
-
'create-line-items': { method: 'POST', path: '/v1/delivery-notes/{noteId}/line-items', summary: 'Add a line item to a delivery note', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderLineItems', 'tagIds', 'tagCodes'] },
|
|
33
|
-
'update-line-items-reorder': { method: 'PATCH', path: '/v1/delivery-notes/{noteId}/line-items/reorder', summary: 'Bulk reorder line items (drag-and-drop)', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['items'] },
|
|
34
|
-
'update-line-items': { method: 'PATCH', path: '/v1/delivery-notes/{noteId}/line-items/{lineItemId}', summary: 'Update a line item on a delivery note', pathParams: ['noteId', 'lineItemId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderLineItems', 'tagIds', 'tagCodes'] },
|
|
35
|
-
'delete-line-items': { method: 'DELETE', path: '/v1/delivery-notes/{noteId}/line-items/{lineItemId}', summary: 'Remove a line item from a delivery note', pathParams: ['noteId', 'lineItemId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'list-notes': { method: 'GET', path: '/v1/delivery-notes/{deliveryNoteId}/notes', summary: 'Get all notes for a delivery note', pathParams: ['deliveryNoteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'create-notes': { method: 'POST', path: '/v1/delivery-notes/{deliveryNoteId}/notes', summary: 'Create a note for a delivery note', pathParams: ['deliveryNoteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'get-notes': { method: 'GET', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Get a specific note for a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
-
'update-notes': { method: 'PATCH', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Update a note for a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
-
'delete-notes': { method: 'DELETE', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Delete a note from a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
-
'list-files': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files', summary: 'List file attachments for a delivery note', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
-
'create-files': { method: 'POST', path: '/v1/delivery-notes/{parentId}/files', summary: 'Upload a file attachment to a delivery note', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
43
|
-
'get-files': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Get a file attachment for a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
44
|
-
'update-files': { method: 'PATCH', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a delivery note', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
45
|
-
'delete-files': { method: 'DELETE', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
46
|
-
'files-download': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/delivery-notes', summary: 'Get all delivery notes with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/delivery-notes', summary: 'Create a new delivery note', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['files', 'notes', 'tagIds', 'tagCodes', 'lineItems'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'create-from-orders': { method: 'POST', path: '/v1/delivery-notes/create-from-orders', summary: 'Create a DRAFT delivery note from several sales orders', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderIds'], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'create-from-invoice': { method: 'POST', path: '/v1/delivery-notes/create-from-invoice', summary: 'Create a DRAFT delivery note from a sales invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'create-invoice': { method: 'POST', path: '/v1/delivery-notes/create-invoice', summary: 'Create ONE draft sales invoice from several delivery notes (same customer)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['deliveryNoteIds'], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'get': { method: 'GET', path: '/v1/delivery-notes/{id}', summary: 'Get a delivery note by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'update': { method: 'PATCH', path: '/v1/delivery-notes/{id}', summary: 'Update a delivery note', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['files', 'notes', 'tagIds', 'tagCodes', 'removeFileIds'], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'delete': { method: 'DELETE', path: '/v1/delivery-notes/{id}', summary: 'Delete a delivery note', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'get-pdf': { method: 'GET', path: '/v1/delivery-notes/{id}/pdf', summary: 'Render a delivery note PDF as the mapped event would, or preview a stored template', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'create-pdf': { method: 'POST', path: '/v1/delivery-notes/{id}/pdf', summary: 'Render a delivery note PDF from unsaved HTML posted in the body', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'submit': { method: 'POST', path: '/v1/delivery-notes/{id}/submit', summary: 'Submit a delivery note for approval (DRAFT → PENDING_APPROVAL)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'approve': { method: 'POST', path: '/v1/delivery-notes/{id}/approve', summary: 'Approve a delivery note (DRAFT or PENDING_APPROVAL → APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'cancel': { method: 'POST', path: '/v1/delivery-notes/{id}/cancel', summary: 'Cancel a delivery note (DRAFT / PENDING_APPROVAL / APPROVED / SHIPPED / DELIVERED → CANCELLED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'replace': { method: 'POST', path: '/v1/delivery-notes/{id}/replace', summary: 'Replace a delivery note (APPROVED / SHIPPED / DELIVERED / CANCELLED → REPLACED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'copy': { method: 'POST', path: '/v1/delivery-notes/{id}/copy', summary: 'Create a copy of a delivery note as a new draft', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'deliver': { method: 'POST', path: '/v1/delivery-notes/{id}/deliver', summary: 'Mark a delivery note as delivered (SHIPPED → DELIVERED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'ship': { method: 'POST', path: '/v1/delivery-notes/{id}/ship', summary: 'Ship a delivery note (APPROVED → SHIPPED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lineItems'], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'send': { method: 'POST', path: '/v1/delivery-notes/{id}/send', summary: 'Send a delivery note to its recipient by email', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['emailCc', 'emailBcc'], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'create-line-items': { method: 'POST', path: '/v1/delivery-notes/{noteId}/line-items', summary: 'Add a line item to a delivery note', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderLineItems', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'update-line-items-reorder': { method: 'PATCH', path: '/v1/delivery-notes/{noteId}/line-items/reorder', summary: 'Bulk reorder line items (drag-and-drop)', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['items'], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'update-line-items': { method: 'PATCH', path: '/v1/delivery-notes/{noteId}/line-items/{lineItemId}', summary: 'Update a line item on a delivery note', pathParams: ['noteId', 'lineItemId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salesOrderLineItems', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'delete-line-items': { method: 'DELETE', path: '/v1/delivery-notes/{noteId}/line-items/{lineItemId}', summary: 'Remove a line item from a delivery note', pathParams: ['noteId', 'lineItemId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'list-notes': { method: 'GET', path: '/v1/delivery-notes/{deliveryNoteId}/notes', summary: 'Get all notes for a delivery note', pathParams: ['deliveryNoteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'create-notes': { method: 'POST', path: '/v1/delivery-notes/{deliveryNoteId}/notes', summary: 'Create a note for a delivery note', pathParams: ['deliveryNoteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'get-notes': { method: 'GET', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Get a specific note for a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
40
|
+
'update-notes': { method: 'PATCH', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Update a note for a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
41
|
+
'delete-notes': { method: 'DELETE', path: '/v1/delivery-notes/{deliveryNoteId}/notes/{noteId}', summary: 'Delete a note from a delivery note', pathParams: ['deliveryNoteId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
42
|
+
'list-files': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files', summary: 'List file attachments for a delivery note', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
43
|
+
'create-files': { method: 'POST', path: '/v1/delivery-notes/{parentId}/files', summary: 'Upload a file attachment to a delivery note', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
44
|
+
'get-files': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Get a file attachment for a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
45
|
+
'update-files': { method: 'PATCH', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a delivery note', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
46
|
+
'delete-files': { method: 'DELETE', path: '/v1/delivery-notes/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
47
|
+
'files-download': { method: 'GET', path: '/v1/delivery-notes/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a delivery note', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
47
48
|
};
|
|
48
49
|
export default class DeliveryNotes extends Command {
|
|
49
50
|
static description = 'Manage delivery notes';
|
|
@@ -65,7 +66,7 @@ export default class DeliveryNotes extends Command {
|
|
|
65
66
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
66
67
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
67
68
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
68
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
69
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
69
70
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
70
71
|
'line-item-id': Flags.string({ description: 'Path param: lineItemId' }),
|
|
71
72
|
'note-id': Flags.string({ description: 'Path param: noteId' }),
|
|
@@ -199,6 +200,17 @@ export default class DeliveryNotes extends Command {
|
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
202
|
}
|
|
203
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
204
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
205
|
+
for (const param of endpoint.specParams) {
|
|
206
|
+
const value = flags[param.flag];
|
|
207
|
+
if (value === undefined || value === '') {
|
|
208
|
+
if (param.required)
|
|
209
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
queryParams[param.name] = value;
|
|
213
|
+
}
|
|
202
214
|
let data;
|
|
203
215
|
if (endpoint.isMultipart) {
|
|
204
216
|
if (!flags.file)
|
|
@@ -219,6 +231,25 @@ export default class DeliveryNotes extends Command {
|
|
|
219
231
|
}
|
|
220
232
|
data = form;
|
|
221
233
|
}
|
|
234
|
+
else if (endpoint.bodyMediaType) {
|
|
235
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
236
|
+
// verbatim, under the content type the endpoint asks for.
|
|
237
|
+
if (flags.file) {
|
|
238
|
+
const fsModule = await import('node:fs');
|
|
239
|
+
try {
|
|
240
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
else if (flags.data) {
|
|
247
|
+
data = flags.data;
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
222
253
|
else if (endpoint.hasBody) {
|
|
223
254
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
224
255
|
// input file — skip the read-as-body branch.
|
|
@@ -314,7 +345,7 @@ export default class DeliveryNotes extends Command {
|
|
|
314
345
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
315
346
|
}
|
|
316
347
|
else if (data) {
|
|
317
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
348
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
318
349
|
}
|
|
319
350
|
process.stderr.write('\n');
|
|
320
351
|
}
|
|
@@ -328,6 +359,7 @@ export default class DeliveryNotes extends Command {
|
|
|
328
359
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
329
360
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
330
361
|
data,
|
|
362
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
331
363
|
contextName: flags.context,
|
|
332
364
|
binary: true,
|
|
333
365
|
});
|
|
@@ -353,6 +385,7 @@ export default class DeliveryNotes extends Command {
|
|
|
353
385
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
354
386
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
355
387
|
data,
|
|
388
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
356
389
|
contextName: flags.context,
|
|
357
390
|
binary: true,
|
|
358
391
|
});
|
|
@@ -373,6 +406,7 @@ export default class DeliveryNotes extends Command {
|
|
|
373
406
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
374
407
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
375
408
|
data,
|
|
409
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
376
410
|
contextName: flags.context,
|
|
377
411
|
acceptAny: true,
|
|
378
412
|
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class DocumentChecksums extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: never[];
|
|
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
|
+
percentage: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
page: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
limit: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
'sort-by': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
filter: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
24
|
+
query: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
fields: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
26
|
+
sanitize: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
meta: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
28
|
+
'show-http-request': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
29
|
+
};
|
|
30
|
+
run(): Promise<void>;
|
|
31
|
+
private runUpsert;
|
|
32
|
+
/**
|
|
33
|
+
* The API's own import: the whole array goes up in one request and comes
|
|
34
|
+
* back as an import run, which records what happened to every record. A bad
|
|
35
|
+
* record lands in errorLog and the rest are still applied, and the run stays
|
|
36
|
+
* readable afterwards with: aderis imports get <id>.
|
|
37
|
+
*/
|
|
38
|
+
private runServerImport;
|
|
39
|
+
/** Renders an import run: its counts, then whatever the server refused. */
|
|
40
|
+
private printImportRun;
|
|
41
|
+
private runExport;
|
|
42
|
+
private runCamt053Import;
|
|
43
|
+
private runNestedUpsert;
|
|
44
|
+
private parseFilterValue;
|
|
45
|
+
/** The page line under a table: which page, how many, and any sums the API returned. */
|
|
46
|
+
private printPageSummary;
|
|
47
|
+
/**
|
|
48
|
+
* The API caps how many records a page may hold. Asking for more and getting
|
|
49
|
+
* fewer looks like "that is everything" unless it is said out loud.
|
|
50
|
+
*/
|
|
51
|
+
private warnShortPage;
|
|
52
|
+
private sanitizeOutput;
|
|
53
|
+
private getColumns;
|
|
54
|
+
private getValue;
|
|
55
|
+
private printTable;
|
|
56
|
+
private printCsv;
|
|
57
|
+
}
|
|
@@ -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.
|
|
@@ -9,19 +10,12 @@ const HAS_EXPORT = false;
|
|
|
9
10
|
const HAS_CAMT053 = false;
|
|
10
11
|
const SERVER_IMPORTS = [];
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
|
-
const SUBCOMMANDS = [...["
|
|
13
|
+
const SUBCOMMANDS = [...["validate"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'
|
|
15
|
-
'create-integrations': { method: 'POST', path: '/v1/auth/integrations', summary: 'Create an integration in the current tenant', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['permissions'] },
|
|
16
|
-
'integrations-disable-all': { method: 'POST', path: '/v1/auth/integrations/disable-all', summary: 'Disable current tenant integrations', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'get-integrations': { method: 'GET', path: '/v1/auth/integrations/{integrationId}', summary: 'Read one current tenant integration', pathParams: ['integrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'list-integrations-secrets': { method: 'GET', path: '/v1/auth/integrations/{integrationId}/secrets', summary: 'List integration secret metadata', pathParams: ['integrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'create-integrations-secrets': { method: 'POST', path: '/v1/auth/integrations/{integrationId}/secrets', summary: 'Issue an integration secret', pathParams: ['integrationId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'delete-integrations-secrets': { method: 'DELETE', path: '/v1/auth/integrations/{integrationId}/secrets/{secretId}', summary: 'Revoke one integration secret', pathParams: ['integrationId', 'secretId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'integrations-disable': { method: 'POST', path: '/v1/auth/integrations/{integrationId}/disable', summary: 'Disable an integration and end its sessions', pathParams: ['integrationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'validate': { method: 'POST', path: '/v1/document-checksums/validate', summary: 'Validate documents against a checksum log', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: 'application/x-ndjson', specParams: [{ "flag": "percentage", "name": "percentage", "required": true }] },
|
|
22
16
|
};
|
|
23
|
-
export default class
|
|
24
|
-
static description = 'Manage
|
|
17
|
+
export default class DocumentChecksums extends Command {
|
|
18
|
+
static description = 'Manage document checksums';
|
|
25
19
|
static examples = [];
|
|
26
20
|
static args = {
|
|
27
21
|
action: Args.string({ description: 'Action: ' + SUBCOMMANDS.join(', '), required: true }),
|
|
@@ -33,9 +27,9 @@ export default class IntegrationIdentities extends Command {
|
|
|
33
27
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
34
28
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
35
29
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
36
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
30
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
37
31
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
38
|
-
'
|
|
32
|
+
'percentage': Flags.string({ description: 'Required. Share of the documents in the log to check, in percent: more than 0, at most 100. The run checks ⌈documents in the log × percentage ÷ 100⌉ documents, at least one, drawn at random with every docume...' }),
|
|
39
33
|
page: Flags.string({ description: 'Page number' }),
|
|
40
34
|
limit: Flags.string({ description: 'Items per page' }),
|
|
41
35
|
include: Flags.string({ description: 'Relations to include' }),
|
|
@@ -49,14 +43,14 @@ export default class IntegrationIdentities extends Command {
|
|
|
49
43
|
'show-http-request': Flags.boolean({ description: 'Show HTTP request details (method, URL, body)' }),
|
|
50
44
|
};
|
|
51
45
|
async run() {
|
|
52
|
-
const { args, flags } = await this.parse(
|
|
46
|
+
const { args, flags } = await this.parse(DocumentChecksums);
|
|
53
47
|
// Bulk actions. 'import' is the API's own endpoint: one request, answered
|
|
54
48
|
// by a run that records what happened to every record. 'upsert' is the CLI
|
|
55
49
|
// looping create/update. A resource has one or the other, never both.
|
|
56
50
|
if (args.action === 'upsert') {
|
|
57
51
|
if (!HAS_UPSERT) {
|
|
58
52
|
this.error(SERVER_IMPORTS.includes('import')
|
|
59
|
-
? 'This resource is imported by the API. Use: aderis
|
|
53
|
+
? 'This resource is imported by the API. Use: aderis document-checksums import --file data.json'
|
|
60
54
|
: 'Upsert needs both a create and an update endpoint, which this resource does not have');
|
|
61
55
|
}
|
|
62
56
|
await this.runUpsert(flags);
|
|
@@ -66,7 +60,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
66
60
|
const suffix = args.action.replace('upsert-', '');
|
|
67
61
|
if (!NESTED_UPSERTS.includes(suffix)) {
|
|
68
62
|
this.error(SERVER_IMPORTS.includes('import-' + suffix)
|
|
69
|
-
? `That resource is imported by the API. Use: aderis
|
|
63
|
+
? `That resource is imported by the API. Use: aderis document-checksums import-${suffix} <id> --file data.json`
|
|
70
64
|
: `Unknown action: ${args.action}. Available: ${SUBCOMMANDS.join(', ')}`);
|
|
71
65
|
}
|
|
72
66
|
await this.runNestedUpsert(suffix, args.id, flags);
|
|
@@ -96,7 +90,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
96
90
|
const suffix = args.action === 'import' ? '' : '-' + args.action.replace('import-', '');
|
|
97
91
|
const loops = args.action === 'import' ? HAS_UPSERT : NESTED_UPSERTS.includes(args.action.replace('import-', ''));
|
|
98
92
|
if (loops) {
|
|
99
|
-
this.error(`This resource has no import endpoint. Use: aderis
|
|
93
|
+
this.error(`This resource has no import endpoint. Use: aderis document-checksums upsert${suffix}${suffix ? ' <id>' : ''} --file data.json`);
|
|
100
94
|
}
|
|
101
95
|
}
|
|
102
96
|
const endpoint = ENDPOINTS[args.action];
|
|
@@ -110,7 +104,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
110
104
|
// First path param always comes from positional argument
|
|
111
105
|
value = args.id;
|
|
112
106
|
if (!value)
|
|
113
|
-
this.error('Missing required argument: id. Usage: aderis
|
|
107
|
+
this.error('Missing required argument: id. Usage: aderis document-checksums <action> <id>');
|
|
114
108
|
}
|
|
115
109
|
else {
|
|
116
110
|
const flagName = param.replace(/\./g, '-').replace(/([A-Z])/g, '-$1').toLowerCase().replace(/^-/, '');
|
|
@@ -165,6 +159,17 @@ export default class IntegrationIdentities extends Command {
|
|
|
165
159
|
}
|
|
166
160
|
}
|
|
167
161
|
}
|
|
162
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
163
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
164
|
+
for (const param of endpoint.specParams) {
|
|
165
|
+
const value = flags[param.flag];
|
|
166
|
+
if (value === undefined || value === '') {
|
|
167
|
+
if (param.required)
|
|
168
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
queryParams[param.name] = value;
|
|
172
|
+
}
|
|
168
173
|
let data;
|
|
169
174
|
if (endpoint.isMultipart) {
|
|
170
175
|
if (!flags.file)
|
|
@@ -185,6 +190,25 @@ export default class IntegrationIdentities extends Command {
|
|
|
185
190
|
}
|
|
186
191
|
data = form;
|
|
187
192
|
}
|
|
193
|
+
else if (endpoint.bodyMediaType) {
|
|
194
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
195
|
+
// verbatim, under the content type the endpoint asks for.
|
|
196
|
+
if (flags.file) {
|
|
197
|
+
const fsModule = await import('node:fs');
|
|
198
|
+
try {
|
|
199
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
else if (flags.data) {
|
|
206
|
+
data = flags.data;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
188
212
|
else if (endpoint.hasBody) {
|
|
189
213
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
190
214
|
// input file — skip the read-as-body branch.
|
|
@@ -280,7 +304,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
280
304
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
281
305
|
}
|
|
282
306
|
else if (data) {
|
|
283
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
307
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
284
308
|
}
|
|
285
309
|
process.stderr.write('\n');
|
|
286
310
|
}
|
|
@@ -294,6 +318,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
294
318
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
295
319
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
296
320
|
data,
|
|
321
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
297
322
|
contextName: flags.context,
|
|
298
323
|
binary: true,
|
|
299
324
|
});
|
|
@@ -319,6 +344,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
319
344
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
320
345
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
321
346
|
data,
|
|
347
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
322
348
|
contextName: flags.context,
|
|
323
349
|
binary: true,
|
|
324
350
|
});
|
|
@@ -339,6 +365,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
339
365
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
340
366
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
341
367
|
data,
|
|
368
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
342
369
|
contextName: flags.context,
|
|
343
370
|
acceptAny: true,
|
|
344
371
|
});
|
|
@@ -641,7 +668,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
641
668
|
let apiPath = endpoint.path;
|
|
642
669
|
if (endpoint.pathParams.length > 0) {
|
|
643
670
|
if (!parentId)
|
|
644
|
-
this.error(`Missing required argument: id. Usage: aderis
|
|
671
|
+
this.error(`Missing required argument: id. Usage: aderis document-checksums ${action} <parent-id> --file data.json`);
|
|
645
672
|
apiPath = apiPath.replace(`{${endpoint.pathParams[0]}}`, parentId);
|
|
646
673
|
}
|
|
647
674
|
// The endpoint takes an array. A single object is wrapped, so importing
|
|
@@ -914,7 +941,7 @@ export default class IntegrationIdentities extends Command {
|
|
|
914
941
|
}
|
|
915
942
|
async runNestedUpsert(suffix, parentId, flags) {
|
|
916
943
|
if (!parentId) {
|
|
917
|
-
this.error(`Missing required argument: id. Usage: aderis
|
|
944
|
+
this.error(`Missing required argument: id. Usage: aderis document-checksums upsert-${suffix} <parent-id> --file data.json`);
|
|
918
945
|
}
|
|
919
946
|
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
920
947
|
if (!context)
|
|
@@ -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,11 +12,11 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "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/dunning-configs', summary: 'List all dunning run configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/dunning-configs', summary: 'Create a new dunning run config', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentMethodIds', 'accessGroupIds'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/dunning-configs/{id}', summary: 'Get a dunning run config by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/dunning-configs/{id}', summary: 'Update a dunning run config', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentMethodIds', 'accessGroupIds'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/dunning-configs/{id}', summary: 'Delete a dunning run config', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/dunning-configs', summary: 'List all dunning run configs', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/dunning-configs', summary: 'Create a new dunning run config', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentMethodIds', 'accessGroupIds'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/dunning-configs/{id}', summary: 'Get a dunning run config by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/dunning-configs/{id}', summary: 'Update a dunning run config', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['paymentMethodIds', 'accessGroupIds'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/dunning-configs/{id}', summary: 'Delete a dunning run config', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
20
|
};
|
|
20
21
|
export default class DunningConfigs extends Command {
|
|
21
22
|
static description = 'Manage dunning configs';
|
|
@@ -37,7 +38,7 @@ export default class DunningConfigs extends Command {
|
|
|
37
38
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
38
39
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
39
40
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
40
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
41
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
41
42
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
42
43
|
page: Flags.string({ description: 'Page number' }),
|
|
43
44
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -168,6 +169,17 @@ export default class DunningConfigs extends Command {
|
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
171
|
}
|
|
172
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
173
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
174
|
+
for (const param of endpoint.specParams) {
|
|
175
|
+
const value = flags[param.flag];
|
|
176
|
+
if (value === undefined || value === '') {
|
|
177
|
+
if (param.required)
|
|
178
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
queryParams[param.name] = value;
|
|
182
|
+
}
|
|
171
183
|
let data;
|
|
172
184
|
if (endpoint.isMultipart) {
|
|
173
185
|
if (!flags.file)
|
|
@@ -188,6 +200,25 @@ export default class DunningConfigs extends Command {
|
|
|
188
200
|
}
|
|
189
201
|
data = form;
|
|
190
202
|
}
|
|
203
|
+
else if (endpoint.bodyMediaType) {
|
|
204
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
205
|
+
// verbatim, under the content type the endpoint asks for.
|
|
206
|
+
if (flags.file) {
|
|
207
|
+
const fsModule = await import('node:fs');
|
|
208
|
+
try {
|
|
209
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else if (flags.data) {
|
|
216
|
+
data = flags.data;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
191
222
|
else if (endpoint.hasBody) {
|
|
192
223
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
193
224
|
// input file — skip the read-as-body branch.
|
|
@@ -283,7 +314,7 @@ export default class DunningConfigs extends Command {
|
|
|
283
314
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
284
315
|
}
|
|
285
316
|
else if (data) {
|
|
286
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
317
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
287
318
|
}
|
|
288
319
|
process.stderr.write('\n');
|
|
289
320
|
}
|
|
@@ -297,6 +328,7 @@ export default class DunningConfigs extends Command {
|
|
|
297
328
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
298
329
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
299
330
|
data,
|
|
331
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
300
332
|
contextName: flags.context,
|
|
301
333
|
binary: true,
|
|
302
334
|
});
|
|
@@ -322,6 +354,7 @@ export default class DunningConfigs extends Command {
|
|
|
322
354
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
323
355
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
324
356
|
data,
|
|
357
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
325
358
|
contextName: flags.context,
|
|
326
359
|
binary: true,
|
|
327
360
|
});
|
|
@@ -342,6 +375,7 @@ export default class DunningConfigs extends Command {
|
|
|
342
375
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
343
376
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
344
377
|
data,
|
|
378
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
345
379
|
contextName: flags.context,
|
|
346
380
|
acceptAny: true,
|
|
347
381
|
});
|