@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.
Files changed (111) hide show
  1. package/README.md +6 -0
  2. package/dist/commands/access-groups.d.ts +1 -0
  3. package/dist/commands/access-groups.js +84 -28
  4. package/dist/commands/{async-endpoints-internal.d.ts → account-transaction-allocations.d.ts} +3 -2
  5. package/dist/commands/{async-endpoints-internal.js → account-transaction-allocations.js} +93 -33
  6. package/dist/commands/account-transactions.d.ts +1 -0
  7. package/dist/commands/account-transactions.js +96 -40
  8. package/dist/commands/accounts.d.ts +1 -0
  9. package/dist/commands/accounts.js +89 -33
  10. package/dist/commands/agent-runs.d.ts +1 -0
  11. package/dist/commands/agent-runs.js +85 -27
  12. package/dist/commands/audit-log.d.ts +1 -0
  13. package/dist/commands/audit-log.js +82 -26
  14. package/dist/commands/auth/login.js +1 -2
  15. package/dist/commands/auth/tenant.d.ts +1 -1
  16. package/dist/commands/auth/tenant.js +11 -11
  17. package/dist/commands/auth.js +1 -1
  18. package/dist/commands/bank-accounts.d.ts +1 -0
  19. package/dist/commands/bank-accounts.js +96 -40
  20. package/dist/commands/bank-integrations.d.ts +1 -0
  21. package/dist/commands/bank-integrations.js +97 -41
  22. package/dist/commands/business-partners---contacts.d.ts +1 -0
  23. package/dist/commands/business-partners---contacts.js +89 -33
  24. package/dist/commands/business-partners.d.ts +1 -0
  25. package/dist/commands/business-partners.js +89 -33
  26. package/dist/commands/credit-card-accounts.d.ts +1 -0
  27. package/dist/commands/credit-card-accounts.js +94 -38
  28. package/dist/commands/documents.d.ts +1 -0
  29. package/dist/commands/documents.js +85 -29
  30. package/dist/commands/dunning-configs.d.ts +1 -0
  31. package/dist/commands/dunning-configs.js +84 -28
  32. package/dist/commands/dunning-reminders.d.ts +1 -0
  33. package/dist/commands/dunning-reminders.js +87 -31
  34. package/dist/commands/dunning-runs.d.ts +1 -0
  35. package/dist/commands/dunning-runs.js +80 -24
  36. package/dist/commands/employees.d.ts +1 -0
  37. package/dist/commands/employees.js +111 -55
  38. package/dist/commands/event-processor-mappings.d.ts +1 -0
  39. package/dist/commands/event-processor-mappings.js +84 -28
  40. package/dist/commands/files-internal.d.ts +1 -0
  41. package/dist/commands/files-internal.js +88 -32
  42. package/dist/commands/health.d.ts +1 -0
  43. package/dist/commands/health.js +84 -28
  44. package/dist/commands/inbox.d.ts +1 -0
  45. package/dist/commands/inbox.js +84 -28
  46. package/dist/commands/integrations.d.ts +1 -0
  47. package/dist/commands/integrations.js +82 -26
  48. package/dist/commands/item-categories.d.ts +1 -0
  49. package/dist/commands/item-categories.js +84 -28
  50. package/dist/commands/items.d.ts +1 -0
  51. package/dist/commands/items.js +84 -28
  52. package/dist/commands/journal-lines.d.ts +1 -0
  53. package/dist/commands/journal-lines.js +80 -24
  54. package/dist/commands/journals.d.ts +1 -0
  55. package/dist/commands/journals.js +98 -42
  56. package/dist/commands/ledgers.d.ts +1 -0
  57. package/dist/commands/ledgers.js +95 -39
  58. package/dist/commands/office-locations.d.ts +1 -0
  59. package/dist/commands/office-locations.js +84 -28
  60. package/dist/commands/payment-method-ledger-mappings.d.ts +1 -0
  61. package/dist/commands/payment-method-ledger-mappings.js +84 -28
  62. package/dist/commands/payment-methods.d.ts +1 -0
  63. package/dist/commands/payment-methods.js +84 -28
  64. package/dist/commands/payment-runs.d.ts +1 -0
  65. package/dist/commands/payment-runs.js +97 -41
  66. package/dist/commands/payment-terms.d.ts +1 -0
  67. package/dist/commands/payment-terms.js +85 -29
  68. package/dist/commands/price-lists.d.ts +1 -0
  69. package/dist/commands/price-lists.js +89 -33
  70. package/dist/commands/processor-mappings.d.ts +1 -0
  71. package/dist/commands/processor-mappings.js +83 -27
  72. package/dist/commands/processors.d.ts +1 -0
  73. package/dist/commands/processors.js +88 -32
  74. package/dist/commands/reconciliation.d.ts +1 -0
  75. package/dist/commands/reconciliation.js +85 -29
  76. package/dist/commands/reports.d.ts +1 -0
  77. package/dist/commands/reports.js +85 -26
  78. package/dist/commands/salary-types.d.ts +1 -0
  79. package/dist/commands/salary-types.js +84 -28
  80. package/dist/commands/sales-invoices.d.ts +1 -0
  81. package/dist/commands/sales-invoices.js +109 -53
  82. package/dist/commands/sales-orders.d.ts +1 -0
  83. package/dist/commands/sales-orders.js +107 -51
  84. package/dist/commands/tags.d.ts +1 -0
  85. package/dist/commands/tags.js +84 -28
  86. package/dist/commands/tax-codes.d.ts +1 -0
  87. package/dist/commands/tax-codes.js +87 -31
  88. package/dist/commands/tax-matrix.d.ts +1 -0
  89. package/dist/commands/tax-matrix.js +84 -28
  90. package/dist/commands/tenants.d.ts +1 -0
  91. package/dist/commands/tenants.js +84 -28
  92. package/dist/commands/text-templates.d.ts +1 -0
  93. package/dist/commands/text-templates.js +84 -28
  94. package/dist/commands/tools.d.ts +1 -0
  95. package/dist/commands/tools.js +81 -25
  96. package/dist/commands/vat-declaration.d.ts +41 -0
  97. package/dist/commands/vat-declaration.js +1079 -0
  98. package/dist/commands/vendor-invoices.d.ts +1 -0
  99. package/dist/commands/vendor-invoices.js +113 -57
  100. package/dist/commands/webhooks.d.ts +1 -0
  101. package/dist/commands/webhooks.js +86 -30
  102. package/dist/commands/workflows.d.ts +1 -0
  103. package/dist/commands/workflows.js +82 -26
  104. package/dist/lib/api-client.d.ts +6 -1
  105. package/dist/lib/api-client.js +23 -5
  106. package/dist/lib/auth.js +18 -0
  107. package/dist/lib/config.js +1 -1
  108. package/oclif.manifest.json +229 -52
  109. package/package.json +15 -13
  110. package/dist/index 2.js +0 -1
  111. package/dist/index.d 2.ts +0 -1
@@ -34,6 +34,7 @@ export default class VendorInvoices extends Command {
34
34
  private runExport;
35
35
  private runCamt053Import;
36
36
  private runNestedImport;
37
+ private parseFilterValue;
37
38
  private filterFields;
38
39
  private sanitizeOutput;
39
40
  private getColumns;
@@ -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
- let value = f.slice(eqIndex + 1);
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
- if (flags.file) {
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
- let value = f.slice(eqIndex + 1);
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) => {
@@ -30,6 +30,7 @@ export default class Webhooks extends Command {
30
30
  private runExport;
31
31
  private runCamt053Import;
32
32
  private runNestedImport;
33
+ private parseFilterValue;
33
34
  private filterFields;
34
35
  private sanitizeOutput;
35
36
  private getColumns;
@@ -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
- let value = f.slice(eqIndex + 1);
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
- if (flags.file) {
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
- let value = f.slice(eqIndex + 1);
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) => {
@@ -30,6 +30,7 @@ export default class Workflows extends Command {
30
30
  private runExport;
31
31
  private runCamt053Import;
32
32
  private runNestedImport;
33
+ private parseFilterValue;
33
34
  private filterFields;
34
35
  private sanitizeOutput;
35
36
  private getColumns;