@aderis-erp/cli 1.0.3 → 1.0.7
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 +6 -0
- package/dist/commands/access-groups.d.ts +1 -0
- package/dist/commands/access-groups.js +84 -28
- package/dist/commands/{async-endpoints-internal.d.ts → account-transaction-allocations.d.ts} +3 -2
- package/dist/commands/{async-endpoints-internal.js → account-transaction-allocations.js} +93 -33
- package/dist/commands/account-transactions.d.ts +1 -0
- package/dist/commands/account-transactions.js +96 -40
- package/dist/commands/accounts.d.ts +1 -0
- package/dist/commands/accounts.js +89 -33
- package/dist/commands/agent-runs.d.ts +1 -0
- package/dist/commands/agent-runs.js +85 -27
- package/dist/commands/audit-log.d.ts +1 -0
- package/dist/commands/audit-log.js +82 -26
- package/dist/commands/auth/login.js +1 -2
- package/dist/commands/auth/tenant.d.ts +1 -1
- package/dist/commands/auth/tenant.js +11 -11
- package/dist/commands/auth.js +1 -1
- package/dist/commands/bank-accounts.d.ts +1 -0
- package/dist/commands/bank-accounts.js +96 -40
- package/dist/commands/bank-integrations.d.ts +1 -0
- package/dist/commands/bank-integrations.js +97 -41
- package/dist/commands/business-partners---contacts.d.ts +1 -0
- package/dist/commands/business-partners---contacts.js +89 -33
- package/dist/commands/business-partners.d.ts +1 -0
- package/dist/commands/business-partners.js +89 -33
- package/dist/commands/credit-card-accounts.d.ts +1 -0
- package/dist/commands/credit-card-accounts.js +94 -38
- package/dist/commands/documents.d.ts +1 -0
- package/dist/commands/documents.js +85 -29
- package/dist/commands/dunning-configs.d.ts +1 -0
- package/dist/commands/dunning-configs.js +84 -28
- package/dist/commands/dunning-reminders.d.ts +1 -0
- package/dist/commands/dunning-reminders.js +87 -31
- package/dist/commands/dunning-runs.d.ts +1 -0
- package/dist/commands/dunning-runs.js +80 -24
- package/dist/commands/employees.d.ts +1 -0
- package/dist/commands/employees.js +111 -55
- package/dist/commands/event-processor-mappings.d.ts +1 -0
- package/dist/commands/event-processor-mappings.js +84 -28
- package/dist/commands/files-internal.d.ts +1 -0
- package/dist/commands/files-internal.js +88 -32
- package/dist/commands/health.d.ts +1 -0
- package/dist/commands/health.js +84 -28
- package/dist/commands/inbox.d.ts +1 -0
- package/dist/commands/inbox.js +84 -28
- package/dist/commands/integrations.d.ts +1 -0
- package/dist/commands/integrations.js +82 -26
- package/dist/commands/item-categories.d.ts +1 -0
- package/dist/commands/item-categories.js +84 -28
- package/dist/commands/items.d.ts +1 -0
- package/dist/commands/items.js +84 -28
- package/dist/commands/journal-lines.d.ts +1 -0
- package/dist/commands/journal-lines.js +80 -24
- package/dist/commands/journals.d.ts +1 -0
- package/dist/commands/journals.js +98 -42
- package/dist/commands/ledgers.d.ts +1 -0
- package/dist/commands/ledgers.js +95 -39
- package/dist/commands/office-locations.d.ts +1 -0
- package/dist/commands/office-locations.js +84 -28
- package/dist/commands/payment-method-ledger-mappings.d.ts +1 -0
- package/dist/commands/payment-method-ledger-mappings.js +84 -28
- package/dist/commands/payment-methods.d.ts +1 -0
- package/dist/commands/payment-methods.js +84 -28
- package/dist/commands/payment-runs.d.ts +1 -0
- package/dist/commands/payment-runs.js +97 -41
- package/dist/commands/payment-terms.d.ts +1 -0
- package/dist/commands/payment-terms.js +85 -29
- package/dist/commands/price-lists.d.ts +1 -0
- package/dist/commands/price-lists.js +89 -33
- package/dist/commands/processor-mappings.d.ts +1 -0
- package/dist/commands/processor-mappings.js +83 -27
- package/dist/commands/processors.d.ts +1 -0
- package/dist/commands/processors.js +88 -32
- package/dist/commands/reconciliation.d.ts +1 -0
- package/dist/commands/reconciliation.js +85 -29
- package/dist/commands/reports.d.ts +1 -0
- package/dist/commands/reports.js +85 -26
- package/dist/commands/salary-types.d.ts +1 -0
- package/dist/commands/salary-types.js +84 -28
- package/dist/commands/sales-invoices.d.ts +1 -0
- package/dist/commands/sales-invoices.js +109 -53
- package/dist/commands/sales-orders.d.ts +1 -0
- package/dist/commands/sales-orders.js +107 -51
- package/dist/commands/tags.d.ts +1 -0
- package/dist/commands/tags.js +84 -28
- package/dist/commands/tax-codes.d.ts +1 -0
- package/dist/commands/tax-codes.js +87 -31
- package/dist/commands/tax-matrix.d.ts +1 -0
- package/dist/commands/tax-matrix.js +84 -28
- package/dist/commands/tenants.d.ts +1 -0
- package/dist/commands/tenants.js +84 -28
- package/dist/commands/text-templates.d.ts +1 -0
- package/dist/commands/text-templates.js +84 -28
- package/dist/commands/tools.d.ts +1 -0
- package/dist/commands/tools.js +81 -25
- package/dist/commands/vat-declaration.d.ts +41 -0
- package/dist/commands/vat-declaration.js +1079 -0
- package/dist/commands/vendor-invoices.d.ts +1 -0
- package/dist/commands/vendor-invoices.js +113 -57
- package/dist/commands/webhooks.d.ts +1 -0
- package/dist/commands/webhooks.js +86 -30
- package/dist/commands/workflows.d.ts +1 -0
- package/dist/commands/workflows.js +82 -26
- package/dist/lib/api-client.d.ts +6 -1
- package/dist/lib/api-client.js +23 -5
- package/dist/lib/auth.js +18 -0
- package/dist/lib/config.js +1 -1
- package/oclif.manifest.json +229 -52
- package/package.json +15 -13
- package/dist/index 2.js +0 -1
- package/dist/index.d 2.ts +0 -1
|
@@ -8,40 +8,40 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = ["line-items", "notes", "files", "payments"];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "submit", "approve", "decline", "book", "cancel", "confirm-cancellation", "change-vendor", "validate", "create-line-items", "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", "list-payments", "create-payments", "get-payments", "update-payments", "delete-payments", "payments-approve", "payments-cancel"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/vendor-invoices', summary: 'Get all vendor invoices with pagination', pathParams: [], hasBody: false, isMultipart: false },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/vendor-invoices', summary: 'Create a new vendor invoice', pathParams: [], hasBody: true, isMultipart: false },
|
|
13
|
-
'get': { method: 'GET', path: '/v1/vendor-invoices/{id}', summary: 'Get a vendor invoice by ID', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
14
|
-
'update': { method: 'PATCH', path: '/v1/vendor-invoices/{id}', summary: 'Update a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
15
|
-
'delete': { method: 'DELETE', path: '/v1/vendor-invoices/{id}', summary: 'Delete a vendor invoice', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
16
|
-
'submit': { method: 'POST', path: '/v1/vendor-invoices/{id}/submit', summary: 'Submit a vendor invoice for approval (transitions DRAFT to PENDING_APPROVAL)', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
17
|
-
'approve': { method: 'POST', path: '/v1/vendor-invoices/{id}/approve', summary: 'Approve a vendor invoice (transitions DRAFT/PENDING_APPROVAL to APPROVED)', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
18
|
-
'decline': { method: 'POST', path: '/v1/vendor-invoices/{id}/decline', summary: 'Decline a vendor invoice (transitions PENDING_APPROVAL to DECLINED)', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
19
|
-
'book': { method: 'POST', path: '/v1/vendor-invoices/{id}/book', summary: 'Manually book a vendor invoice (dispatch to ledger-booking-agent)', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
20
|
-
'cancel': { method: 'POST', path: '/v1/vendor-invoices/{id}/cancel', summary: 'Cancel a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
21
|
-
'confirm-cancellation': { method: 'POST', path: '/v1/vendor-invoices/{id}/confirm-cancellation', summary: 'Confirm bank cancellation for a vendor invoice (PENDING_CANCELLATION to CANCELLED)', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
22
|
-
'change-vendor': { method: 'POST', path: '/v1/vendor-invoices/{id}/change-vendor', summary: 'Change the vendor on a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
23
|
-
'validate': { method: 'POST', path: '/v1/vendor-invoices/{id}/validate', summary: 'Validate a vendor invoice update without persisting changes', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
24
|
-
'create-line-items': { method: 'POST', path: '/v1/vendor-invoices/{invoiceId}/line-items', summary: 'Add a line item to a vendor invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false },
|
|
25
|
-
'update-line-items': { method: 'PATCH', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Update a line item on a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: true, isMultipart: false },
|
|
26
|
-
'delete-line-items': { method: 'DELETE', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Remove a line item from a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: false, isMultipart: false },
|
|
27
|
-
'list-notes': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Get all notes for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: false, isMultipart: false },
|
|
28
|
-
'create-notes': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Create a note for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: true, isMultipart: false },
|
|
29
|
-
'get-notes': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Get a specific note for a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: false, isMultipart: false },
|
|
30
|
-
'update-notes': { method: 'PATCH', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Update a note for a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: true, isMultipart: false },
|
|
31
|
-
'delete-notes': { method: 'DELETE', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Delete a note from a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: false, isMultipart: false },
|
|
32
|
-
'list-files': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files', summary: 'List file attachments for a vendor invoice', pathParams: ['parentId'], hasBody: false, isMultipart: false },
|
|
33
|
-
'create-files': { method: 'POST', path: '/v1/vendor-invoices/{parentId}/files', summary: 'Upload a file attachment to a vendor invoice', pathParams: ['parentId'], hasBody: false, isMultipart: true },
|
|
34
|
-
'get-files': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Get a file attachment for a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false },
|
|
35
|
-
'update-files': { method: 'PATCH', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false },
|
|
36
|
-
'delete-files': { method: 'DELETE', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false },
|
|
37
|
-
'files-download': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false },
|
|
38
|
-
'list-payments': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments', summary: 'Get all payments for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: false, isMultipart: false },
|
|
39
|
-
'create-payments': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments', summary: 'Create a payment for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: true, isMultipart: false },
|
|
40
|
-
'get-payments': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Get a specific payment for a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false },
|
|
41
|
-
'update-payments': { method: 'PATCH', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Update a payment for a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false },
|
|
42
|
-
'delete-payments': { method: 'DELETE', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Delete a payment from a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false },
|
|
43
|
-
'payments-approve': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/approve', summary: 'Approve a payment entry (OPEN → APPROVED)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false },
|
|
44
|
-
'payments-cancel': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/cancel', summary: 'Cancel a sent payment entry (SENT -> ERROR)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/vendor-invoices', summary: 'Get all vendor invoices with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/vendor-invoices', summary: 'Create a new vendor invoice', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'payments'] },
|
|
13
|
+
'get': { method: 'GET', path: '/v1/vendor-invoices/{id}', summary: 'Get a vendor invoice by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
+
'update': { method: 'PATCH', path: '/v1/vendor-invoices/{id}', summary: 'Update a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
15
|
+
'delete': { method: 'DELETE', path: '/v1/vendor-invoices/{id}', summary: 'Delete a vendor invoice', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
+
'submit': { method: 'POST', path: '/v1/vendor-invoices/{id}/submit', summary: 'Submit a vendor invoice for approval (transitions DRAFT to PENDING_APPROVAL)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
17
|
+
'approve': { method: 'POST', path: '/v1/vendor-invoices/{id}/approve', summary: 'Approve a vendor invoice (transitions DRAFT/PENDING_APPROVAL to APPROVED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
18
|
+
'decline': { method: 'POST', path: '/v1/vendor-invoices/{id}/decline', summary: 'Decline a vendor invoice (transitions PENDING_APPROVAL to DECLINED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
19
|
+
'book': { method: 'POST', path: '/v1/vendor-invoices/{id}/book', summary: 'Manually book a vendor invoice (dispatch to ledger-booking-agent)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
20
|
+
'cancel': { method: 'POST', path: '/v1/vendor-invoices/{id}/cancel', summary: 'Cancel a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
21
|
+
'confirm-cancellation': { method: 'POST', path: '/v1/vendor-invoices/{id}/confirm-cancellation', summary: 'Confirm bank cancellation for a vendor invoice (PENDING_CANCELLATION to CANCELLED)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
22
|
+
'change-vendor': { method: 'POST', path: '/v1/vendor-invoices/{id}/change-vendor', summary: 'Change the vendor on a vendor invoice', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
23
|
+
'validate': { method: 'POST', path: '/v1/vendor-invoices/{id}/validate', summary: 'Validate a vendor invoice update without persisting changes', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['totalAmountByTaxRate', 'files', 'notes', 'lineItems', 'tagIds', 'removeFileIds'] },
|
|
24
|
+
'create-line-items': { method: 'POST', path: '/v1/vendor-invoices/{invoiceId}/line-items', summary: 'Add a line item to a vendor invoice', pathParams: ['invoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
25
|
+
'update-line-items': { method: 'PATCH', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Update a line item on a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
26
|
+
'delete-line-items': { method: 'DELETE', path: '/v1/vendor-invoices/{invoiceId}/line-items/{lineItemId}', summary: 'Remove a line item from a vendor invoice', pathParams: ['invoiceId', 'lineItemId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
27
|
+
'list-notes': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Get all notes for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
28
|
+
'create-notes': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes', summary: 'Create a note for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
29
|
+
'get-notes': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Get a specific note for a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
30
|
+
'update-notes': { method: 'PATCH', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Update a note for a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
31
|
+
'delete-notes': { method: 'DELETE', path: '/v1/vendor-invoices/{vendorInvoiceId}/notes/{noteId}', summary: 'Delete a note from a vendor invoice', pathParams: ['vendorInvoiceId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
32
|
+
'list-files': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files', summary: 'List file attachments for a vendor invoice', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
33
|
+
'create-files': { method: 'POST', path: '/v1/vendor-invoices/{parentId}/files', summary: 'Upload a file attachment to a vendor invoice', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, bodyArrayFields: [] },
|
|
34
|
+
'get-files': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Get a file attachment for a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
35
|
+
'update-files': { method: 'PATCH', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
36
|
+
'delete-files': { method: 'DELETE', path: '/v1/vendor-invoices/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
37
|
+
'files-download': { method: 'GET', path: '/v1/vendor-invoices/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a vendor invoice', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
38
|
+
'list-payments': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments', summary: 'Get all payments for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
39
|
+
'create-payments': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments', summary: 'Create a payment for a vendor invoice', pathParams: ['vendorInvoiceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
40
|
+
'get-payments': { method: 'GET', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Get a specific payment for a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
41
|
+
'update-payments': { method: 'PATCH', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Update a payment for a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
42
|
+
'delete-payments': { method: 'DELETE', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}', summary: 'Delete a payment from a vendor invoice', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
43
|
+
'payments-approve': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/approve', summary: 'Approve a payment entry (OPEN → APPROVED)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
44
|
+
'payments-cancel': { method: 'POST', path: '/v1/vendor-invoices/{vendorInvoiceId}/payments/{paymentId}/cancel', summary: 'Cancel a sent payment entry (SENT -> ERROR)', pathParams: ['vendorInvoiceId', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
45
45
|
};
|
|
46
46
|
export default class VendorInvoices extends Command {
|
|
47
47
|
static description = 'Manage vendor invoices';
|
|
@@ -114,11 +114,6 @@ export default class VendorInvoices extends Command {
|
|
|
114
114
|
const endpoint = ENDPOINTS[args.action];
|
|
115
115
|
if (!endpoint)
|
|
116
116
|
this.error(`Unknown action: ${args.action}. Available: ${SUBCOMMANDS.join(', ')}`);
|
|
117
|
-
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
118
|
-
if (!context)
|
|
119
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
120
|
-
if (!context.tokens)
|
|
121
|
-
this.error('Not logged in. Run: aderis auth login');
|
|
122
117
|
let apiPath = endpoint.path;
|
|
123
118
|
for (let i = 0; i < endpoint.pathParams.length; i++) {
|
|
124
119
|
const param = endpoint.pathParams[i];
|
|
@@ -137,6 +132,11 @@ export default class VendorInvoices extends Command {
|
|
|
137
132
|
}
|
|
138
133
|
apiPath = apiPath.replace(`{${param}}`, String(value));
|
|
139
134
|
}
|
|
135
|
+
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
136
|
+
if (!context)
|
|
137
|
+
this.error('No context configured. Run: aderis auth login --new');
|
|
138
|
+
if (!context.tokens)
|
|
139
|
+
this.error('Not logged in. Run: aderis auth login');
|
|
140
140
|
const queryParams = {};
|
|
141
141
|
if (flags.page)
|
|
142
142
|
queryParams.page = flags.page;
|
|
@@ -163,15 +163,7 @@ export default class VendorInvoices extends Command {
|
|
|
163
163
|
if (eqIndex === -1)
|
|
164
164
|
this.error(`Invalid --filter format: ${f}. Use: --filter key=value`);
|
|
165
165
|
const key = f.slice(0, eqIndex);
|
|
166
|
-
|
|
167
|
-
// Check for operator prefix (with or without $)
|
|
168
|
-
const opMatch = value.match(/^\$?(eq|ne|in|like|gt|gte|lt|lte|null):/);
|
|
169
|
-
if (opMatch) {
|
|
170
|
-
value = `\$${opMatch[1]}:${value.slice(opMatch[0].length)}`;
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
value = `\$eq:${value}`;
|
|
174
|
-
}
|
|
166
|
+
const value = this.parseFilterValue(f.slice(eqIndex + 1));
|
|
175
167
|
const filterKey = `filter.${key}`;
|
|
176
168
|
if (filterKey in queryParams) {
|
|
177
169
|
// Multiple filters on same field: collect as array
|
|
@@ -204,7 +196,9 @@ export default class VendorInvoices extends Command {
|
|
|
204
196
|
data = form;
|
|
205
197
|
}
|
|
206
198
|
else if (endpoint.hasBody) {
|
|
207
|
-
|
|
199
|
+
// For binary-response endpoints, --file is the output path, not a JSON
|
|
200
|
+
// input file — skip the read-as-body branch.
|
|
201
|
+
if (flags.file && !endpoint.isBinaryResponse) {
|
|
208
202
|
const fsModule = await import('node:fs');
|
|
209
203
|
try {
|
|
210
204
|
data = JSON.parse(fsModule.readFileSync(flags.file, 'utf-8'));
|
|
@@ -226,6 +220,7 @@ export default class VendorInvoices extends Command {
|
|
|
226
220
|
if (!data)
|
|
227
221
|
data = {};
|
|
228
222
|
const body = data;
|
|
223
|
+
const arrayFields = new Set(endpoint.bodyArrayFields);
|
|
229
224
|
for (const pair of flags.set) {
|
|
230
225
|
const eqIndex = pair.indexOf('=');
|
|
231
226
|
if (eqIndex === -1)
|
|
@@ -237,6 +232,19 @@ export default class VendorInvoices extends Command {
|
|
|
237
232
|
value = JSON.parse(value);
|
|
238
233
|
}
|
|
239
234
|
catch { /* keep as string */ }
|
|
235
|
+
// For top-level keys typed as array in the API schema, split bare
|
|
236
|
+
// comma-separated input (e.g. "1171,1170" -> ["1171","1170"]) and
|
|
237
|
+
// wrap a lone scalar in a single-element array. Skips when --set
|
|
238
|
+
// already provided a JSON array.
|
|
239
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
240
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
241
|
+
if (typeof value === 'string') {
|
|
242
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
243
|
+
}
|
|
244
|
+
else if (value !== undefined && value !== null) {
|
|
245
|
+
value = [value];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
240
248
|
// Support nested keys like "address.city"
|
|
241
249
|
const keys = key.split('.');
|
|
242
250
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
@@ -287,6 +295,26 @@ export default class VendorInvoices extends Command {
|
|
|
287
295
|
process.stderr.write('\n');
|
|
288
296
|
}
|
|
289
297
|
try {
|
|
298
|
+
// Binary response: download to file
|
|
299
|
+
if (endpoint.isBinaryResponse) {
|
|
300
|
+
if (!flags.file) {
|
|
301
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
|
|
302
|
+
}
|
|
303
|
+
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
304
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
305
|
+
data,
|
|
306
|
+
contextName: flags.context,
|
|
307
|
+
binary: true,
|
|
308
|
+
});
|
|
309
|
+
const fsModule = await import('node:fs');
|
|
310
|
+
const binData = binResponse.data;
|
|
311
|
+
const buffer = Buffer.isBuffer(binData)
|
|
312
|
+
? binData
|
|
313
|
+
: Buffer.from(binData);
|
|
314
|
+
fsModule.writeFileSync(flags.file, buffer);
|
|
315
|
+
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
290
318
|
const response = await apiRequest(endpoint.method, apiPath, {
|
|
291
319
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
292
320
|
data,
|
|
@@ -377,6 +405,7 @@ export default class VendorInvoices extends Command {
|
|
|
377
405
|
}
|
|
378
406
|
else if (flags.set && flags.set.length > 0) {
|
|
379
407
|
const item = {};
|
|
408
|
+
const arrayFields = new Set(ENDPOINTS['create']?.bodyArrayFields ?? []);
|
|
380
409
|
for (const pair of flags.set) {
|
|
381
410
|
const eqIndex = pair.indexOf('=');
|
|
382
411
|
if (eqIndex === -1)
|
|
@@ -387,6 +416,15 @@ export default class VendorInvoices extends Command {
|
|
|
387
416
|
value = JSON.parse(value);
|
|
388
417
|
}
|
|
389
418
|
catch { /* keep as string */ }
|
|
419
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
420
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
421
|
+
if (typeof value === 'string') {
|
|
422
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
423
|
+
}
|
|
424
|
+
else if (value !== undefined && value !== null) {
|
|
425
|
+
value = [value];
|
|
426
|
+
}
|
|
427
|
+
}
|
|
390
428
|
const keys = key.split('.');
|
|
391
429
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
392
430
|
this.error(`Invalid --set key: ${key}`);
|
|
@@ -536,14 +574,7 @@ export default class VendorInvoices extends Command {
|
|
|
536
574
|
if (eqIndex === -1)
|
|
537
575
|
this.error(`Invalid --filter format: ${f}. Use: --filter key=value`);
|
|
538
576
|
const key = f.slice(0, eqIndex);
|
|
539
|
-
|
|
540
|
-
const opMatch = value.match(/^\$?(eq|ne|in|like|gt|gte|lt|lte|null):/);
|
|
541
|
-
if (opMatch) {
|
|
542
|
-
value = `\$${opMatch[1]}:${value.slice(opMatch[0].length)}`;
|
|
543
|
-
}
|
|
544
|
-
else {
|
|
545
|
-
value = `\$eq:${value}`;
|
|
546
|
-
}
|
|
577
|
+
const value = this.parseFilterValue(f.slice(eqIndex + 1));
|
|
547
578
|
const filterKey = `filter.${key}`;
|
|
548
579
|
if (filterKey in baseParams) {
|
|
549
580
|
const existing = baseParams[filterKey];
|
|
@@ -720,6 +751,7 @@ export default class VendorInvoices extends Command {
|
|
|
720
751
|
}
|
|
721
752
|
else if (flags.set && flags.set.length > 0) {
|
|
722
753
|
const item = {};
|
|
754
|
+
const arrayFields = new Set(ENDPOINTS[`create-${suffix}`]?.bodyArrayFields ?? []);
|
|
723
755
|
for (const pair of flags.set) {
|
|
724
756
|
const eqIndex = pair.indexOf('=');
|
|
725
757
|
if (eqIndex === -1)
|
|
@@ -730,6 +762,15 @@ export default class VendorInvoices extends Command {
|
|
|
730
762
|
value = JSON.parse(value);
|
|
731
763
|
}
|
|
732
764
|
catch { /* keep as string */ }
|
|
765
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
766
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
767
|
+
if (typeof value === 'string') {
|
|
768
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
769
|
+
}
|
|
770
|
+
else if (value !== undefined && value !== null) {
|
|
771
|
+
value = [value];
|
|
772
|
+
}
|
|
773
|
+
}
|
|
733
774
|
const keys = key.split('.');
|
|
734
775
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
735
776
|
this.error(`Invalid --set key: ${key}`);
|
|
@@ -849,6 +890,21 @@ export default class VendorInvoices extends Command {
|
|
|
849
890
|
this.log('');
|
|
850
891
|
this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
|
|
851
892
|
}
|
|
893
|
+
parseFilterValue(value) {
|
|
894
|
+
// Recognises the nestjs-paginate operator set (with or without the leading $)
|
|
895
|
+
// and recursively unwraps chained operators like 'not:null' -> '$not:$null'
|
|
896
|
+
// or 'not:like:John' -> '$not:$like:John'. Falls back to '$eq:<value>' when
|
|
897
|
+
// no operator prefix is present.
|
|
898
|
+
const opRe = /^\$?(and|or|not|eq|gt|gte|in|null|lt|lte|btw|ne|ilike|like|sw|contains)(?::|$)/;
|
|
899
|
+
const m = value.match(opRe);
|
|
900
|
+
if (!m)
|
|
901
|
+
return `\$eq:${value}`;
|
|
902
|
+
const op = m[1];
|
|
903
|
+
const rest = value.slice(m[0].length);
|
|
904
|
+
if (rest === '')
|
|
905
|
+
return `\$${op}`;
|
|
906
|
+
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
907
|
+
}
|
|
852
908
|
filterFields(data, fields) {
|
|
853
909
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
854
910
|
const pick = (obj, keys) => {
|
|
@@ -8,13 +8,13 @@ const HAS_CAMT053 = false;
|
|
|
8
8
|
const NESTED_IMPORTS = [];
|
|
9
9
|
const SUBCOMMANDS = [...["list", "create", "events", "events-relations", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
|
|
10
10
|
const ENDPOINTS = {
|
|
11
|
-
'list': { method: 'GET', path: '/v1/webhooks', summary: 'List all webhook subscriptions', pathParams: [], hasBody: false, isMultipart: false },
|
|
12
|
-
'create': { method: 'POST', path: '/v1/webhooks', summary: 'Create a new webhook subscription', pathParams: [], hasBody: true, isMultipart: false },
|
|
13
|
-
'events': { method: 'GET', path: '/v1/webhooks/events', summary: 'Get available event types', pathParams: [], hasBody: false, isMultipart: false },
|
|
14
|
-
'events-relations': { method: 'GET', path: '/v1/webhooks/events/{eventType}/relations', summary: 'Get valid relations for an event type', pathParams: ['eventType'], hasBody: false, isMultipart: false },
|
|
15
|
-
'get': { method: 'GET', path: '/v1/webhooks/{id}', summary: 'Get a webhook subscription by ID', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
16
|
-
'update': { method: 'PATCH', path: '/v1/webhooks/{id}', summary: 'Update a webhook subscription', pathParams: ['id'], hasBody: true, isMultipart: false },
|
|
17
|
-
'delete': { method: 'DELETE', path: '/v1/webhooks/{id}', summary: 'Delete a webhook subscription', pathParams: ['id'], hasBody: false, isMultipart: false },
|
|
11
|
+
'list': { method: 'GET', path: '/v1/webhooks', summary: 'List all webhook subscriptions', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
12
|
+
'create': { method: 'POST', path: '/v1/webhooks', summary: 'Create a new webhook subscription', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tenantIds'] },
|
|
13
|
+
'events': { method: 'GET', path: '/v1/webhooks/events', summary: 'Get available event types', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
14
|
+
'events-relations': { method: 'GET', path: '/v1/webhooks/events/{eventType}/relations', summary: 'Get valid relations for an event type', pathParams: ['eventType'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
15
|
+
'get': { method: 'GET', path: '/v1/webhooks/{id}', summary: 'Get a webhook subscription by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
16
|
+
'update': { method: 'PATCH', path: '/v1/webhooks/{id}', summary: 'Update a webhook subscription', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tenantIds'] },
|
|
17
|
+
'delete': { method: 'DELETE', path: '/v1/webhooks/{id}', summary: 'Delete a webhook subscription', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
|
|
18
18
|
};
|
|
19
19
|
export default class Webhooks extends Command {
|
|
20
20
|
static description = 'Manage webhooks';
|
|
@@ -83,11 +83,6 @@ export default class Webhooks extends Command {
|
|
|
83
83
|
const endpoint = ENDPOINTS[args.action];
|
|
84
84
|
if (!endpoint)
|
|
85
85
|
this.error(`Unknown action: ${args.action}. Available: ${SUBCOMMANDS.join(', ')}`);
|
|
86
|
-
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
87
|
-
if (!context)
|
|
88
|
-
this.error('No context configured. Run: aderis auth login --new');
|
|
89
|
-
if (!context.tokens)
|
|
90
|
-
this.error('Not logged in. Run: aderis auth login');
|
|
91
86
|
let apiPath = endpoint.path;
|
|
92
87
|
for (let i = 0; i < endpoint.pathParams.length; i++) {
|
|
93
88
|
const param = endpoint.pathParams[i];
|
|
@@ -106,6 +101,11 @@ export default class Webhooks extends Command {
|
|
|
106
101
|
}
|
|
107
102
|
apiPath = apiPath.replace(`{${param}}`, String(value));
|
|
108
103
|
}
|
|
104
|
+
const context = flags.context ? getContext(flags.context) : getCurrentContext();
|
|
105
|
+
if (!context)
|
|
106
|
+
this.error('No context configured. Run: aderis auth login --new');
|
|
107
|
+
if (!context.tokens)
|
|
108
|
+
this.error('Not logged in. Run: aderis auth login');
|
|
109
109
|
const queryParams = {};
|
|
110
110
|
if (flags.page)
|
|
111
111
|
queryParams.page = flags.page;
|
|
@@ -132,15 +132,7 @@ export default class Webhooks extends Command {
|
|
|
132
132
|
if (eqIndex === -1)
|
|
133
133
|
this.error(`Invalid --filter format: ${f}. Use: --filter key=value`);
|
|
134
134
|
const key = f.slice(0, eqIndex);
|
|
135
|
-
|
|
136
|
-
// Check for operator prefix (with or without $)
|
|
137
|
-
const opMatch = value.match(/^\$?(eq|ne|in|like|gt|gte|lt|lte|null):/);
|
|
138
|
-
if (opMatch) {
|
|
139
|
-
value = `\$${opMatch[1]}:${value.slice(opMatch[0].length)}`;
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
value = `\$eq:${value}`;
|
|
143
|
-
}
|
|
135
|
+
const value = this.parseFilterValue(f.slice(eqIndex + 1));
|
|
144
136
|
const filterKey = `filter.${key}`;
|
|
145
137
|
if (filterKey in queryParams) {
|
|
146
138
|
// Multiple filters on same field: collect as array
|
|
@@ -173,7 +165,9 @@ export default class Webhooks extends Command {
|
|
|
173
165
|
data = form;
|
|
174
166
|
}
|
|
175
167
|
else if (endpoint.hasBody) {
|
|
176
|
-
|
|
168
|
+
// For binary-response endpoints, --file is the output path, not a JSON
|
|
169
|
+
// input file — skip the read-as-body branch.
|
|
170
|
+
if (flags.file && !endpoint.isBinaryResponse) {
|
|
177
171
|
const fsModule = await import('node:fs');
|
|
178
172
|
try {
|
|
179
173
|
data = JSON.parse(fsModule.readFileSync(flags.file, 'utf-8'));
|
|
@@ -195,6 +189,7 @@ export default class Webhooks extends Command {
|
|
|
195
189
|
if (!data)
|
|
196
190
|
data = {};
|
|
197
191
|
const body = data;
|
|
192
|
+
const arrayFields = new Set(endpoint.bodyArrayFields);
|
|
198
193
|
for (const pair of flags.set) {
|
|
199
194
|
const eqIndex = pair.indexOf('=');
|
|
200
195
|
if (eqIndex === -1)
|
|
@@ -206,6 +201,19 @@ export default class Webhooks extends Command {
|
|
|
206
201
|
value = JSON.parse(value);
|
|
207
202
|
}
|
|
208
203
|
catch { /* keep as string */ }
|
|
204
|
+
// For top-level keys typed as array in the API schema, split bare
|
|
205
|
+
// comma-separated input (e.g. "1171,1170" -> ["1171","1170"]) and
|
|
206
|
+
// wrap a lone scalar in a single-element array. Skips when --set
|
|
207
|
+
// already provided a JSON array.
|
|
208
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
209
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
210
|
+
if (typeof value === 'string') {
|
|
211
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
212
|
+
}
|
|
213
|
+
else if (value !== undefined && value !== null) {
|
|
214
|
+
value = [value];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
209
217
|
// Support nested keys like "address.city"
|
|
210
218
|
const keys = key.split('.');
|
|
211
219
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
@@ -256,6 +264,26 @@ export default class Webhooks extends Command {
|
|
|
256
264
|
process.stderr.write('\n');
|
|
257
265
|
}
|
|
258
266
|
try {
|
|
267
|
+
// Binary response: download to file
|
|
268
|
+
if (endpoint.isBinaryResponse) {
|
|
269
|
+
if (!flags.file) {
|
|
270
|
+
this.error(`Endpoint returns a binary file. Specify the output path with -f / --file (e.g. -f report.xlsx).`);
|
|
271
|
+
}
|
|
272
|
+
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
273
|
+
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
274
|
+
data,
|
|
275
|
+
contextName: flags.context,
|
|
276
|
+
binary: true,
|
|
277
|
+
});
|
|
278
|
+
const fsModule = await import('node:fs');
|
|
279
|
+
const binData = binResponse.data;
|
|
280
|
+
const buffer = Buffer.isBuffer(binData)
|
|
281
|
+
? binData
|
|
282
|
+
: Buffer.from(binData);
|
|
283
|
+
fsModule.writeFileSync(flags.file, buffer);
|
|
284
|
+
this.log(`Saved ${buffer.length} bytes to ${flags.file}`);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
259
287
|
const response = await apiRequest(endpoint.method, apiPath, {
|
|
260
288
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
261
289
|
data,
|
|
@@ -346,6 +374,7 @@ export default class Webhooks extends Command {
|
|
|
346
374
|
}
|
|
347
375
|
else if (flags.set && flags.set.length > 0) {
|
|
348
376
|
const item = {};
|
|
377
|
+
const arrayFields = new Set(ENDPOINTS['create']?.bodyArrayFields ?? []);
|
|
349
378
|
for (const pair of flags.set) {
|
|
350
379
|
const eqIndex = pair.indexOf('=');
|
|
351
380
|
if (eqIndex === -1)
|
|
@@ -356,6 +385,15 @@ export default class Webhooks extends Command {
|
|
|
356
385
|
value = JSON.parse(value);
|
|
357
386
|
}
|
|
358
387
|
catch { /* keep as string */ }
|
|
388
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
389
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
390
|
+
if (typeof value === 'string') {
|
|
391
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
392
|
+
}
|
|
393
|
+
else if (value !== undefined && value !== null) {
|
|
394
|
+
value = [value];
|
|
395
|
+
}
|
|
396
|
+
}
|
|
359
397
|
const keys = key.split('.');
|
|
360
398
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
361
399
|
this.error(`Invalid --set key: ${key}`);
|
|
@@ -505,14 +543,7 @@ export default class Webhooks extends Command {
|
|
|
505
543
|
if (eqIndex === -1)
|
|
506
544
|
this.error(`Invalid --filter format: ${f}. Use: --filter key=value`);
|
|
507
545
|
const key = f.slice(0, eqIndex);
|
|
508
|
-
|
|
509
|
-
const opMatch = value.match(/^\$?(eq|ne|in|like|gt|gte|lt|lte|null):/);
|
|
510
|
-
if (opMatch) {
|
|
511
|
-
value = `\$${opMatch[1]}:${value.slice(opMatch[0].length)}`;
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
value = `\$eq:${value}`;
|
|
515
|
-
}
|
|
546
|
+
const value = this.parseFilterValue(f.slice(eqIndex + 1));
|
|
516
547
|
const filterKey = `filter.${key}`;
|
|
517
548
|
if (filterKey in baseParams) {
|
|
518
549
|
const existing = baseParams[filterKey];
|
|
@@ -689,6 +720,7 @@ export default class Webhooks extends Command {
|
|
|
689
720
|
}
|
|
690
721
|
else if (flags.set && flags.set.length > 0) {
|
|
691
722
|
const item = {};
|
|
723
|
+
const arrayFields = new Set(ENDPOINTS[`create-${suffix}`]?.bodyArrayFields ?? []);
|
|
692
724
|
for (const pair of flags.set) {
|
|
693
725
|
const eqIndex = pair.indexOf('=');
|
|
694
726
|
if (eqIndex === -1)
|
|
@@ -699,6 +731,15 @@ export default class Webhooks extends Command {
|
|
|
699
731
|
value = JSON.parse(value);
|
|
700
732
|
}
|
|
701
733
|
catch { /* keep as string */ }
|
|
734
|
+
const isArrayField = !key.includes('.') && arrayFields.has(key);
|
|
735
|
+
if (isArrayField && !Array.isArray(value)) {
|
|
736
|
+
if (typeof value === 'string') {
|
|
737
|
+
value = value.split(',').map(v => v.trim()).filter(v => v.length > 0);
|
|
738
|
+
}
|
|
739
|
+
else if (value !== undefined && value !== null) {
|
|
740
|
+
value = [value];
|
|
741
|
+
}
|
|
742
|
+
}
|
|
702
743
|
const keys = key.split('.');
|
|
703
744
|
if (keys.some(k => k === '__proto__' || k === 'constructor' || k === 'prototype')) {
|
|
704
745
|
this.error(`Invalid --set key: ${key}`);
|
|
@@ -818,6 +859,21 @@ export default class Webhooks extends Command {
|
|
|
818
859
|
this.log('');
|
|
819
860
|
this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
|
|
820
861
|
}
|
|
862
|
+
parseFilterValue(value) {
|
|
863
|
+
// Recognises the nestjs-paginate operator set (with or without the leading $)
|
|
864
|
+
// and recursively unwraps chained operators like 'not:null' -> '$not:$null'
|
|
865
|
+
// or 'not:like:John' -> '$not:$like:John'. Falls back to '$eq:<value>' when
|
|
866
|
+
// no operator prefix is present.
|
|
867
|
+
const opRe = /^\$?(and|or|not|eq|gt|gte|in|null|lt|lte|btw|ne|ilike|like|sw|contains)(?::|$)/;
|
|
868
|
+
const m = value.match(opRe);
|
|
869
|
+
if (!m)
|
|
870
|
+
return `\$eq:${value}`;
|
|
871
|
+
const op = m[1];
|
|
872
|
+
const rest = value.slice(m[0].length);
|
|
873
|
+
if (rest === '')
|
|
874
|
+
return `\$${op}`;
|
|
875
|
+
return opRe.test(rest) ? `\$${op}:${this.parseFilterValue(rest)}` : `\$${op}:${rest}`;
|
|
876
|
+
}
|
|
821
877
|
filterFields(data, fields) {
|
|
822
878
|
const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
|
|
823
879
|
const pick = (obj, keys) => {
|