@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,41 +12,41 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["notes", "files", "files-parentId"];
|
|
12
13
|
const SUBCOMMANDS = [...["list-notes", "create-notes", "update-notes", "delete-notes", "notices-dismiss", "notices-restore", "list", "create", "get", "update", "delete", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-bookings", "update-bookings", "list-entries", "get-entries", "update-entries", "entries-exclude", "entries-include", "list-files-parentId", "create-files-parentId", "get-files-parentId", "update-files-parentId", "delete-files-parentId", "files-download-parentId", "approve", "cancel", "payments", "recalculate-payment-status", "payslips-send"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list-notes': { method: 'GET', path: '/v1/payroll-runs/notes', summary: 'List payroll notes (paginated), newest effectiveDate first', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create-notes': { method: 'POST', path: '/v1/payroll-runs/notes', summary: 'Create a payroll note', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'update-notes': { method: 'PATCH', path: '/v1/payroll-runs/notes/{noteId}', summary: 'Update a payroll note', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'delete-notes': { method: 'DELETE', path: '/v1/payroll-runs/notes/{noteId}', summary: 'Delete a payroll note', pathParams: ['noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'notices-dismiss': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/notices/{noticeId}/dismiss', summary: 'Dismiss one review notice on a DRAFT run', pathParams: ['payrollRunId', 'noticeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'notices-restore': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/notices/{noticeId}/restore', summary: 'Restore a dismissed review notice on a DRAFT run', pathParams: ['payrollRunId', 'noticeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'list': { method: 'GET', path: '/v1/payroll-runs', summary: 'List payroll runs (paginated), each with its computed totals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'create': { method: 'POST', path: '/v1/payroll-runs', summary: 'Create a payroll run with its entries and DRAFT payments', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['entries'] },
|
|
22
|
-
'get': { method: 'GET', path: '/v1/payroll-runs/{id}', summary: 'Get a payroll run with its totals, previous-run comparison and payments', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'update': { method: 'PATCH', path: '/v1/payroll-runs/{id}', summary: 'Change the payout date, description or bank account of a DRAFT payroll run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'delete': { method: 'DELETE', path: '/v1/payroll-runs/{id}', summary: 'Delete a DRAFT payroll run', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'list-files': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files', summary: 'List file attachments for a payroll run', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'create-files': { method: 'POST', path: '/v1/payroll-runs/{parentId}/files', summary: 'Upload a file attachment to a payroll run', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'get-files': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Get a file attachment for a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'update-files': { method: 'PATCH', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a payroll run', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'delete-files': { method: 'DELETE', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'files-download': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'list-bookings': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/bookings', summary: 'List a payroll run\'s bookings, one per open ledger, and the clearing check', pathParams: ['payrollRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'update-bookings': { method: 'PATCH', path: '/v1/payroll-runs/{payrollRunId}/bookings/{bookingId}', summary: 'Replace the lines of one of a DRAFT run\'s bookings by hand', pathParams: ['payrollRunId', 'bookingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'] },
|
|
33
|
-
'list-entries': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/entries', summary: 'List a payroll run\'s entries, each with its previous-run comparison', pathParams: ['payrollRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'get-entries': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}', summary: 'Get one payroll run entry with its previous-run comparison', pathParams: ['payrollRunId', 'entryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'update-entries': { method: 'PATCH', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}', summary: 'Change a DRAFT entry\'s notes or payoutDate', pathParams: ['payrollRunId', 'entryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'entries-exclude': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}/exclude', summary: 'Exclude a DRAFT entry from the payout', pathParams: ['payrollRunId', 'entryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'entries-include': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}/include', summary: 'Include a previously excluded DRAFT entry back into the payout', pathParams: ['payrollRunId', 'entryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'list-files-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files', summary: 'List file attachments for a payroll run entry', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
-
'create-files-parentId': { method: 'POST', path: '/v1/payroll-run-entries/{parentId}/files', summary: 'Upload a file attachment to a payroll run entry', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
-
'get-files-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Get a file attachment for a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
-
'update-files-parentId': { method: 'PATCH', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
-
'delete-files-parentId': { method: 'DELETE', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
43
|
-
'files-download-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
44
|
-
'approve': { method: 'POST', path: '/v1/payroll-runs/{id}/approve', summary: 'Approve a DRAFT payroll run and open its payment run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
45
|
-
'cancel': { method: 'POST', path: '/v1/payroll-runs/{id}/cancel', summary: 'Cancel an APPROVED payroll run whose payments have not been executed', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
46
|
-
'payments': { method: 'GET', path: '/v1/payroll-runs/{id}/payments', summary: 'List every payment of a payroll run', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
47
|
-
'recalculate-payment-status': { method: 'POST', path: '/v1/payroll-runs/{id}/recalculate-payment-status', summary: 'Recalculate a payroll run\'s payment status from its payments', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
48
|
-
'payslips-send': { method: 'POST', path: '/v1/payroll-runs/{id}/payslips/send', summary: 'Email employees their payslips for an APPROVED payroll run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['entryIds'] },
|
|
15
|
+
'list-notes': { method: 'GET', path: '/v1/payroll-runs/notes', summary: 'List payroll notes (paginated), newest effectiveDate first', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create-notes': { method: 'POST', path: '/v1/payroll-runs/notes', summary: 'Create a payroll note', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'update-notes': { method: 'PATCH', path: '/v1/payroll-runs/notes/{noteId}', summary: 'Update a payroll note', pathParams: ['noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'delete-notes': { method: 'DELETE', path: '/v1/payroll-runs/notes/{noteId}', summary: 'Delete a payroll note', pathParams: ['noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'notices-dismiss': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/notices/{noticeId}/dismiss', summary: 'Dismiss one review notice on a DRAFT run', pathParams: ['payrollRunId', 'noticeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'notices-restore': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/notices/{noticeId}/restore', summary: 'Restore a dismissed review notice on a DRAFT run', pathParams: ['payrollRunId', 'noticeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'list': { method: 'GET', path: '/v1/payroll-runs', summary: 'List payroll runs (paginated), each with its computed totals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'create': { method: 'POST', path: '/v1/payroll-runs', summary: 'Create a payroll run with its entries and DRAFT payments', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['entries'], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'get': { method: 'GET', path: '/v1/payroll-runs/{id}', summary: 'Get a payroll run with its totals, previous-run comparison and payments', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'update': { method: 'PATCH', path: '/v1/payroll-runs/{id}', summary: 'Change the payout date, description or bank account of a DRAFT payroll run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'delete': { method: 'DELETE', path: '/v1/payroll-runs/{id}', summary: 'Delete a DRAFT payroll run', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'list-files': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files', summary: 'List file attachments for a payroll run', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'create-files': { method: 'POST', path: '/v1/payroll-runs/{parentId}/files', summary: 'Upload a file attachment to a payroll run', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'get-files': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Get a file attachment for a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'update-files': { method: 'PATCH', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a payroll run', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'delete-files': { method: 'DELETE', path: '/v1/payroll-runs/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'files-download': { method: 'GET', path: '/v1/payroll-runs/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a payroll run', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'list-bookings': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/bookings', summary: 'List a payroll run\'s bookings, one per open ledger, and the clearing check', pathParams: ['payrollRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'update-bookings': { method: 'PATCH', path: '/v1/payroll-runs/{payrollRunId}/bookings/{bookingId}', summary: 'Replace the lines of one of a DRAFT run\'s bookings by hand', pathParams: ['payrollRunId', 'bookingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['lines'], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'list-entries': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/entries', summary: 'List a payroll run\'s entries, each with its previous-run comparison', pathParams: ['payrollRunId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'get-entries': { method: 'GET', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}', summary: 'Get one payroll run entry with its previous-run comparison', pathParams: ['payrollRunId', 'entryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'update-entries': { method: 'PATCH', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}', summary: 'Change a DRAFT entry\'s notes or payoutDate', pathParams: ['payrollRunId', 'entryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'entries-exclude': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}/exclude', summary: 'Exclude a DRAFT entry from the payout', pathParams: ['payrollRunId', 'entryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'entries-include': { method: 'POST', path: '/v1/payroll-runs/{payrollRunId}/entries/{entryId}/include', summary: 'Include a previously excluded DRAFT entry back into the payout', pathParams: ['payrollRunId', 'entryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'list-files-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files', summary: 'List file attachments for a payroll run entry', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
40
|
+
'create-files-parentId': { method: 'POST', path: '/v1/payroll-run-entries/{parentId}/files', summary: 'Upload a file attachment to a payroll run entry', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
41
|
+
'get-files-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Get a file attachment for a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
42
|
+
'update-files-parentId': { method: 'PATCH', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
43
|
+
'delete-files-parentId': { method: 'DELETE', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
44
|
+
'files-download-parentId': { method: 'GET', path: '/v1/payroll-run-entries/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a payroll run entry', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
45
|
+
'approve': { method: 'POST', path: '/v1/payroll-runs/{id}/approve', summary: 'Approve a DRAFT payroll run and open its payment run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
46
|
+
'cancel': { method: 'POST', path: '/v1/payroll-runs/{id}/cancel', summary: 'Cancel an APPROVED payroll run whose payments have not been executed', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
47
|
+
'payments': { method: 'GET', path: '/v1/payroll-runs/{id}/payments', summary: 'List every payment of a payroll run', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
48
|
+
'recalculate-payment-status': { method: 'POST', path: '/v1/payroll-runs/{id}/recalculate-payment-status', summary: 'Recalculate a payroll run\'s payment status from its payments', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
49
|
+
'payslips-send': { method: 'POST', path: '/v1/payroll-runs/{id}/payslips/send', summary: 'Email employees their payslips for an APPROVED payroll run', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['entryIds'], bodyMediaType: '', specParams: [] },
|
|
49
50
|
};
|
|
50
51
|
export default class PayrollRuns extends Command {
|
|
51
52
|
static description = 'Manage payroll runs';
|
|
@@ -67,7 +68,7 @@ export default class PayrollRuns extends Command {
|
|
|
67
68
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
68
69
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
69
70
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
70
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
71
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
71
72
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
72
73
|
'notice-id': Flags.string({ description: 'Path param: noticeId' }),
|
|
73
74
|
'file-id': Flags.string({ description: 'Path param: fileId' }),
|
|
@@ -202,6 +203,17 @@ export default class PayrollRuns extends Command {
|
|
|
202
203
|
}
|
|
203
204
|
}
|
|
204
205
|
}
|
|
206
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
207
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
208
|
+
for (const param of endpoint.specParams) {
|
|
209
|
+
const value = flags[param.flag];
|
|
210
|
+
if (value === undefined || value === '') {
|
|
211
|
+
if (param.required)
|
|
212
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
queryParams[param.name] = value;
|
|
216
|
+
}
|
|
205
217
|
let data;
|
|
206
218
|
if (endpoint.isMultipart) {
|
|
207
219
|
if (!flags.file)
|
|
@@ -222,6 +234,25 @@ export default class PayrollRuns extends Command {
|
|
|
222
234
|
}
|
|
223
235
|
data = form;
|
|
224
236
|
}
|
|
237
|
+
else if (endpoint.bodyMediaType) {
|
|
238
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
239
|
+
// verbatim, under the content type the endpoint asks for.
|
|
240
|
+
if (flags.file) {
|
|
241
|
+
const fsModule = await import('node:fs');
|
|
242
|
+
try {
|
|
243
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else if (flags.data) {
|
|
250
|
+
data = flags.data;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
225
256
|
else if (endpoint.hasBody) {
|
|
226
257
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
227
258
|
// input file — skip the read-as-body branch.
|
|
@@ -317,7 +348,7 @@ export default class PayrollRuns extends Command {
|
|
|
317
348
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
318
349
|
}
|
|
319
350
|
else if (data) {
|
|
320
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
351
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
321
352
|
}
|
|
322
353
|
process.stderr.write('\n');
|
|
323
354
|
}
|
|
@@ -331,6 +362,7 @@ export default class PayrollRuns extends Command {
|
|
|
331
362
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
332
363
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
333
364
|
data,
|
|
365
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
334
366
|
contextName: flags.context,
|
|
335
367
|
binary: true,
|
|
336
368
|
});
|
|
@@ -356,6 +388,7 @@ export default class PayrollRuns extends Command {
|
|
|
356
388
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
357
389
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
358
390
|
data,
|
|
391
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
359
392
|
contextName: flags.context,
|
|
360
393
|
binary: true,
|
|
361
394
|
});
|
|
@@ -376,6 +409,7 @@ export default class PayrollRuns extends Command {
|
|
|
376
409
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
377
410
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
378
411
|
data,
|
|
412
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
379
413
|
contextName: flags.context,
|
|
380
414
|
acceptAny: true,
|
|
381
415
|
});
|
|
@@ -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,7 +12,7 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/permissions', summary: 'List permissions selectable for tenant-created roles', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/permissions', summary: 'List permissions selectable for tenant-created roles', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
15
16
|
};
|
|
16
17
|
export default class Permissions extends Command {
|
|
17
18
|
static description = 'Manage permissions';
|
|
@@ -29,7 +30,7 @@ export default class Permissions extends Command {
|
|
|
29
30
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
30
31
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
31
32
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
32
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
33
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
33
34
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
34
35
|
page: Flags.string({ description: 'Page number' }),
|
|
35
36
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -160,6 +161,17 @@ export default class Permissions extends Command {
|
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
}
|
|
164
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
165
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
166
|
+
for (const param of endpoint.specParams) {
|
|
167
|
+
const value = flags[param.flag];
|
|
168
|
+
if (value === undefined || value === '') {
|
|
169
|
+
if (param.required)
|
|
170
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
queryParams[param.name] = value;
|
|
174
|
+
}
|
|
163
175
|
let data;
|
|
164
176
|
if (endpoint.isMultipart) {
|
|
165
177
|
if (!flags.file)
|
|
@@ -180,6 +192,25 @@ export default class Permissions extends Command {
|
|
|
180
192
|
}
|
|
181
193
|
data = form;
|
|
182
194
|
}
|
|
195
|
+
else if (endpoint.bodyMediaType) {
|
|
196
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
197
|
+
// verbatim, under the content type the endpoint asks for.
|
|
198
|
+
if (flags.file) {
|
|
199
|
+
const fsModule = await import('node:fs');
|
|
200
|
+
try {
|
|
201
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (flags.data) {
|
|
208
|
+
data = flags.data;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
183
214
|
else if (endpoint.hasBody) {
|
|
184
215
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
185
216
|
// input file — skip the read-as-body branch.
|
|
@@ -275,7 +306,7 @@ export default class Permissions extends Command {
|
|
|
275
306
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
276
307
|
}
|
|
277
308
|
else if (data) {
|
|
278
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
309
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
279
310
|
}
|
|
280
311
|
process.stderr.write('\n');
|
|
281
312
|
}
|
|
@@ -289,6 +320,7 @@ export default class Permissions extends Command {
|
|
|
289
320
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
290
321
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
291
322
|
data,
|
|
323
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
292
324
|
contextName: flags.context,
|
|
293
325
|
binary: true,
|
|
294
326
|
});
|
|
@@ -314,6 +346,7 @@ export default class Permissions extends Command {
|
|
|
314
346
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
315
347
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
316
348
|
data,
|
|
349
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
317
350
|
contextName: flags.context,
|
|
318
351
|
binary: true,
|
|
319
352
|
});
|
|
@@ -334,6 +367,7 @@ export default class Permissions extends Command {
|
|
|
334
367
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
335
368
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
336
369
|
data,
|
|
370
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
337
371
|
contextName: flags.context,
|
|
338
372
|
acceptAny: true,
|
|
339
373
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command, Args, Flags } from '@oclif/core';
|
|
2
2
|
import { apiRequest, ApiError, isTextualMediaType, normalizeSortBy } from '../lib/api-client.js';
|
|
3
3
|
import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
|
|
4
|
+
import { resolveUserPath } from '../lib/paths.js';
|
|
4
5
|
// 'upsert' loops create/update from the CLI, one request per record. It exists
|
|
5
6
|
// only where the API has no import endpoint of its own; those keep the name
|
|
6
7
|
// 'import' and are listed in SERVER_IMPORTS.
|
|
@@ -11,18 +12,18 @@ const SERVER_IMPORTS = ["import", "import-prices"];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "list-prices", "create-prices", "get-prices", "update-prices", "delete-prices", "import", "import-prices"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/price-lists', summary: 'Get all price lists with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/price-lists', summary: 'Create a new price list', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/price-lists/{id}', summary: 'Get a price list by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/price-lists/{id}', summary: 'Update a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/price-lists/{id}', summary: 'Delete a price list', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'list-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices', summary: 'Get all prices in a price list with pagination', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'create-prices': { method: 'POST', path: '/v1/price-lists/{id}/prices', summary: 'Create a new price in a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'get-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Get a price by ID', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'update-prices': { method: 'PATCH', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Update a price', pathParams: ['id', 'priceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'delete-prices': { method: 'DELETE', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Delete a price', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'import': { method: 'POST', path: '/v1/price-lists/import', summary: 'Import price lists', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'import-prices': { method: 'POST', path: '/v1/price-lists/{priceListId}/prices/import', summary: 'Import prices into a price list', pathParams: ['priceListId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/price-lists', summary: 'Get all price lists with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/price-lists', summary: 'Create a new price list', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/price-lists/{id}', summary: 'Get a price list by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/price-lists/{id}', summary: 'Update a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/price-lists/{id}', summary: 'Delete a price list', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'list-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices', summary: 'Get all prices in a price list with pagination', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'create-prices': { method: 'POST', path: '/v1/price-lists/{id}/prices', summary: 'Create a new price in a price list', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'get-prices': { method: 'GET', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Get a price by ID', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'update-prices': { method: 'PATCH', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Update a price', pathParams: ['id', 'priceId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'delete-prices': { method: 'DELETE', path: '/v1/price-lists/{id}/prices/{priceId}', summary: 'Delete a price', pathParams: ['id', 'priceId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'import': { method: 'POST', path: '/v1/price-lists/import', summary: 'Import price lists', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'import-prices': { method: 'POST', path: '/v1/price-lists/{priceListId}/prices/import', summary: 'Import prices into a price list', pathParams: ['priceListId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
27
|
};
|
|
27
28
|
export default class PriceLists extends Command {
|
|
28
29
|
static description = 'Manage price lists';
|
|
@@ -44,7 +45,7 @@ export default class PriceLists extends Command {
|
|
|
44
45
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
45
46
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
46
47
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
47
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
48
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
48
49
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
49
50
|
mode: Flags.string({ description: 'Import mode: upsert (default) creates, updates or skips each record; create refuses records that already exist; update refuses records that do not', options: ['upsert', 'create', 'update'] }),
|
|
50
51
|
reference: Flags.string({ description: 'Caller-defined text stored on the import run, for tracking and filtering' }),
|
|
@@ -180,6 +181,17 @@ export default class PriceLists extends Command {
|
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
}
|
|
184
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
185
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
186
|
+
for (const param of endpoint.specParams) {
|
|
187
|
+
const value = flags[param.flag];
|
|
188
|
+
if (value === undefined || value === '') {
|
|
189
|
+
if (param.required)
|
|
190
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
queryParams[param.name] = value;
|
|
194
|
+
}
|
|
183
195
|
let data;
|
|
184
196
|
if (endpoint.isMultipart) {
|
|
185
197
|
if (!flags.file)
|
|
@@ -200,6 +212,25 @@ export default class PriceLists extends Command {
|
|
|
200
212
|
}
|
|
201
213
|
data = form;
|
|
202
214
|
}
|
|
215
|
+
else if (endpoint.bodyMediaType) {
|
|
216
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
217
|
+
// verbatim, under the content type the endpoint asks for.
|
|
218
|
+
if (flags.file) {
|
|
219
|
+
const fsModule = await import('node:fs');
|
|
220
|
+
try {
|
|
221
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else if (flags.data) {
|
|
228
|
+
data = flags.data;
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
203
234
|
else if (endpoint.hasBody) {
|
|
204
235
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
205
236
|
// input file — skip the read-as-body branch.
|
|
@@ -295,7 +326,7 @@ export default class PriceLists extends Command {
|
|
|
295
326
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
296
327
|
}
|
|
297
328
|
else if (data) {
|
|
298
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
329
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
299
330
|
}
|
|
300
331
|
process.stderr.write('\n');
|
|
301
332
|
}
|
|
@@ -309,6 +340,7 @@ export default class PriceLists extends Command {
|
|
|
309
340
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
310
341
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
311
342
|
data,
|
|
343
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
312
344
|
contextName: flags.context,
|
|
313
345
|
binary: true,
|
|
314
346
|
});
|
|
@@ -334,6 +366,7 @@ export default class PriceLists extends Command {
|
|
|
334
366
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
335
367
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
336
368
|
data,
|
|
369
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
337
370
|
contextName: flags.context,
|
|
338
371
|
binary: true,
|
|
339
372
|
});
|
|
@@ -354,6 +387,7 @@ export default class PriceLists extends Command {
|
|
|
354
387
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
355
388
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
356
389
|
data,
|
|
390
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
357
391
|
contextName: flags.context,
|
|
358
392
|
acceptAny: true,
|
|
359
393
|
});
|
|
@@ -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,10 +12,10 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "update", "delete"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/processor-mappings', summary: 'List all document type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/processor-mappings', summary: 'Create a new document type processor mapping', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'] },
|
|
16
|
-
'update': { method: 'PATCH', path: '/v1/processor-mappings/{id}', summary: 'Update a document type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'] },
|
|
17
|
-
'delete': { method: 'DELETE', path: '/v1/processor-mappings/{id}', summary: 'Delete a document type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/processor-mappings', summary: 'List all document type processor mappings for the tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/processor-mappings', summary: 'Create a new document type processor mapping', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'update': { method: 'PATCH', path: '/v1/processor-mappings/{id}', summary: 'Update a document type processor mapping', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['documentTypes'], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'delete': { method: 'DELETE', path: '/v1/processor-mappings/{id}', summary: 'Delete a document type processor mapping', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
19
|
};
|
|
19
20
|
export default class ProcessorMappings extends Command {
|
|
20
21
|
static description = 'Manage processor mappings';
|
|
@@ -35,7 +36,7 @@ export default class ProcessorMappings extends Command {
|
|
|
35
36
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
36
37
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
37
38
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
38
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
39
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
39
40
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
40
41
|
page: Flags.string({ description: 'Page number' }),
|
|
41
42
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -166,6 +167,17 @@ export default class ProcessorMappings extends Command {
|
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
169
|
}
|
|
170
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
171
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
172
|
+
for (const param of endpoint.specParams) {
|
|
173
|
+
const value = flags[param.flag];
|
|
174
|
+
if (value === undefined || value === '') {
|
|
175
|
+
if (param.required)
|
|
176
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
queryParams[param.name] = value;
|
|
180
|
+
}
|
|
169
181
|
let data;
|
|
170
182
|
if (endpoint.isMultipart) {
|
|
171
183
|
if (!flags.file)
|
|
@@ -186,6 +198,25 @@ export default class ProcessorMappings extends Command {
|
|
|
186
198
|
}
|
|
187
199
|
data = form;
|
|
188
200
|
}
|
|
201
|
+
else if (endpoint.bodyMediaType) {
|
|
202
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
203
|
+
// verbatim, under the content type the endpoint asks for.
|
|
204
|
+
if (flags.file) {
|
|
205
|
+
const fsModule = await import('node:fs');
|
|
206
|
+
try {
|
|
207
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (flags.data) {
|
|
214
|
+
data = flags.data;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
189
220
|
else if (endpoint.hasBody) {
|
|
190
221
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
191
222
|
// input file — skip the read-as-body branch.
|
|
@@ -281,7 +312,7 @@ export default class ProcessorMappings extends Command {
|
|
|
281
312
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
282
313
|
}
|
|
283
314
|
else if (data) {
|
|
284
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
315
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
285
316
|
}
|
|
286
317
|
process.stderr.write('\n');
|
|
287
318
|
}
|
|
@@ -295,6 +326,7 @@ export default class ProcessorMappings extends Command {
|
|
|
295
326
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
296
327
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
297
328
|
data,
|
|
329
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
298
330
|
contextName: flags.context,
|
|
299
331
|
binary: true,
|
|
300
332
|
});
|
|
@@ -320,6 +352,7 @@ export default class ProcessorMappings extends Command {
|
|
|
320
352
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
321
353
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
322
354
|
data,
|
|
355
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
323
356
|
contextName: flags.context,
|
|
324
357
|
binary: true,
|
|
325
358
|
});
|
|
@@ -340,6 +373,7 @@ export default class ProcessorMappings extends Command {
|
|
|
340
373
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
341
374
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
342
375
|
data,
|
|
376
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
343
377
|
contextName: flags.context,
|
|
344
378
|
acceptAny: true,
|
|
345
379
|
});
|