@aderis-erp/cli 1.1.4 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.js +47 -13
- 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.js +57 -23
- package/dist/commands/currencies.js +37 -3
- package/dist/commands/custody-accounts.js +41 -7
- package/dist/commands/dashboards.js +52 -18
- package/dist/commands/delivery-notes.js +69 -35
- package/dist/commands/document-checksums.d.ts +1 -0
- package/dist/commands/document-checksums.js +38 -3
- 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.js +41 -7
- package/dist/commands/financial-instruments.js +41 -7
- 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/kpis.js +44 -10
- package/dist/commands/ledgers.js +83 -49
- package/dist/commands/my-account.js +54 -20
- package/dist/commands/notifications.js +37 -3
- 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.js +38 -4
- 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 +49 -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 +81 -47
- package/dist/commands/webhooks.js +43 -9
- package/dist/commands/work-summary.js +37 -3
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +16 -0
- package/dist/lib/production-guard.js +2 -0
- package/oclif.manifest.json +199 -2
- package/package.json +9 -3
package/dist/commands/kpis.js
CHANGED
|
@@ -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,14 +12,14 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get-by-code", "update", "archive", "restore", "duplicate", "evaluate"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/kpis', summary: 'List the KPIs that can be evaluated', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/kpis', summary: 'Define a KPI', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'get-by-code': { method: 'GET', path: '/v1/kpis/by-code/{code}', summary: 'Describe one KPI', pathParams: ['code'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/kpis/{id}', summary: 'Change a KPI definition', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'archive': { method: 'POST', path: '/v1/kpis/{id}/archive', summary: 'Archive a KPI definition', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'restore': { method: 'POST', path: '/v1/kpis/{id}/restore', summary: 'Restore an archived KPI', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'duplicate': { method: 'POST', path: '/v1/kpis/{id}/duplicate', summary: 'Copy a KPI definition', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'evaluate': { method: 'POST', path: '/v1/kpis/evaluate', summary: 'Evaluate KPIs for one period, with comparisons', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['codes', 'compare'] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/kpis', summary: 'List the KPIs that can be evaluated', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/kpis', summary: 'Define a KPI', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get-by-code': { method: 'GET', path: '/v1/kpis/by-code/{code}', summary: 'Describe one KPI', pathParams: ['code'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/kpis/{id}', summary: 'Change a KPI definition', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'archive': { method: 'POST', path: '/v1/kpis/{id}/archive', summary: 'Archive a KPI definition', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'restore': { method: 'POST', path: '/v1/kpis/{id}/restore', summary: 'Restore an archived KPI', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'duplicate': { method: 'POST', path: '/v1/kpis/{id}/duplicate', summary: 'Copy a KPI definition', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'evaluate': { method: 'POST', path: '/v1/kpis/evaluate', summary: 'Evaluate KPIs for one period, with comparisons', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['codes', 'compare'], bodyMediaType: '', specParams: [] },
|
|
22
23
|
};
|
|
23
24
|
export default class Kpis extends Command {
|
|
24
25
|
static description = 'Manage kpis';
|
|
@@ -39,7 +40,7 @@ export default class Kpis extends Command {
|
|
|
39
40
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
40
41
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
41
42
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
42
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
43
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
43
44
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
44
45
|
page: Flags.string({ description: 'Page number' }),
|
|
45
46
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -170,6 +171,17 @@ export default class Kpis extends Command {
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
}
|
|
174
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
175
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
176
|
+
for (const param of endpoint.specParams) {
|
|
177
|
+
const value = flags[param.flag];
|
|
178
|
+
if (value === undefined || value === '') {
|
|
179
|
+
if (param.required)
|
|
180
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
queryParams[param.name] = value;
|
|
184
|
+
}
|
|
173
185
|
let data;
|
|
174
186
|
if (endpoint.isMultipart) {
|
|
175
187
|
if (!flags.file)
|
|
@@ -190,6 +202,25 @@ export default class Kpis extends Command {
|
|
|
190
202
|
}
|
|
191
203
|
data = form;
|
|
192
204
|
}
|
|
205
|
+
else if (endpoint.bodyMediaType) {
|
|
206
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
207
|
+
// verbatim, under the content type the endpoint asks for.
|
|
208
|
+
if (flags.file) {
|
|
209
|
+
const fsModule = await import('node:fs');
|
|
210
|
+
try {
|
|
211
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else if (flags.data) {
|
|
218
|
+
data = flags.data;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
193
224
|
else if (endpoint.hasBody) {
|
|
194
225
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
195
226
|
// input file — skip the read-as-body branch.
|
|
@@ -285,7 +316,7 @@ export default class Kpis extends Command {
|
|
|
285
316
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
286
317
|
}
|
|
287
318
|
else if (data) {
|
|
288
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
319
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
289
320
|
}
|
|
290
321
|
process.stderr.write('\n');
|
|
291
322
|
}
|
|
@@ -299,6 +330,7 @@ export default class Kpis extends Command {
|
|
|
299
330
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
300
331
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
301
332
|
data,
|
|
333
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
302
334
|
contextName: flags.context,
|
|
303
335
|
binary: true,
|
|
304
336
|
});
|
|
@@ -324,6 +356,7 @@ export default class Kpis extends Command {
|
|
|
324
356
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
325
357
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
326
358
|
data,
|
|
359
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
327
360
|
contextName: flags.context,
|
|
328
361
|
binary: true,
|
|
329
362
|
});
|
|
@@ -344,6 +377,7 @@ export default class Kpis extends Command {
|
|
|
344
377
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
345
378
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
346
379
|
data,
|
|
380
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
347
381
|
contextName: flags.context,
|
|
348
382
|
acceptAny: true,
|
|
349
383
|
});
|
package/dist/commands/ledgers.js
CHANGED
|
@@ -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,53 +12,53 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["month-end-closings", "month-end-closings-accruals", "month-end-closings-notes", "notes", "closings"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "list-month-end-closings", "create-month-end-closings", "get-month-end-closings", "update-month-end-closings", "delete-month-end-closings", "month-end-closings-complete", "create-month-end-closings-provisional-booking", "delete-month-end-closings-provisional-booking", "month-end-closings-reopen", "list-month-end-closings-accruals", "create-month-end-closings-accruals", "update-month-end-closings-accruals", "delete-month-end-closings-accruals", "month-end-closings-accruals-accept", "month-end-closings-accruals-dismiss", "list-month-end-closings-accrual-accounts", "list-month-end-closings-findings", "update-month-end-closings-findings", "list-month-end-closings-notes", "create-month-end-closings-notes", "get-month-end-closings-notes", "update-month-end-closings-notes", "delete-month-end-closings-notes", "update-month-end-closings-agent-results", "month-end-closings-agent-run", "get-fx-rate", "replace-fx-rate-providers", "replace-closing-fx-rate-providers", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-closings", "create-closings", "get-closings", "update-closings", "closings-close", "closings-reopen", "list-posting-runs", "create-posting-runs", "posting-runs"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/ledgers', summary: 'List all ledgers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/ledgers', summary: 'Create a new ledger', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes', 'fxRateProviders', 'closingFxRateProviders'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/ledgers/{id}', summary: 'Get a ledger by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/ledgers/{id}', summary: 'Update a ledger', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fxRateProviders', 'closingFxRateProviders'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/ledgers/{id}', summary: 'Delete a ledger', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'list-month-end-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings', summary: 'List the month-end closings of a ledger, newest month first', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'create-month-end-closings': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings', summary: 'Create a DRAFT month-end closing for one calendar month', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'get-month-end-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Get one month-end closing', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'update-month-end-closings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Change the description, postApprovedJournals, accrueOpenTransactions or the open-transaction accounts of a closing', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'delete-month-end-closings': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Delete a DRAFT closing with its accrual rows, findings, notes and its provisional journal; no other journal is touched', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'month-end-closings-complete': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/complete', summary: 'Complete a DRAFT or REOPENED closing: delete its provisional journal, then book the accrual journal (posted) — with the open transactions\' line pairs when accrueOpenTransactions is on — one reversal journal per reversal date (APPROVED) and the FX revaluation journal (posted) in this ledger, and store the bank and FX rows as they are now; the ledger\'s lockedDate is not changed', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'create-month-end-closings-provisional-booking': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/provisional-booking', summary: 'Book (or book again) the provisional journal of a DRAFT or REOPENED closing: deletes the existing one, then books one APPROVED journal dated the month end with the lines Complete would book there now (accepted accruals, open-transaction pairs, FX revaluation); no reversal, nothing posted, no row marked BOOKED, and none when there is no line. The closing\'s figures ignore it; Complete deletes it first', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'delete-month-end-closings-provisional-booking': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/provisional-booking', summary: 'Delete the provisional journal of a DRAFT or REOPENED closing, if it has one', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'month-end-closings-reopen': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/reopen', summary: 'Reopen a COMPLETED closing: its rows are computed live again and journals keeps naming the last completion\'s journals; no journal and not the ledger\'s lockedDate is changed', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'list-month-end-closings-accruals': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals', summary: 'List the accrual rows of a closing by account code, then title', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'create-month-end-closings-accruals': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals', summary: 'Add a manual accrual row; it starts ACCEPTED', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'update-month-end-closings-accruals': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}', summary: 'Change a PROPOSED or ACCEPTED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'delete-month-end-closings-accruals': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}', summary: 'Delete a PROPOSED, ACCEPTED or DISMISSED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'month-end-closings-accruals-accept': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}/accept', summary: 'Accept a PROPOSED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'month-end-closings-accruals-dismiss': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}/dismiss', summary: 'Dismiss a PROPOSED accrual row; the agent does not propose it again', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'list-month-end-closings-accrual-accounts': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accrual-accounts', summary: 'One entry per accrual account of the ledger: the period\'s movement against the average of the three months before, what is accrued, the difference and the month-end instructions; with include=partners also the movement per business partner', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'list-month-end-closings-findings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/findings', summary: 'List the agent\'s findings on a closing: HIGH, MEDIUM, LOW, then by creation time', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'update-month-end-closings-findings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/findings/{findingId}', summary: 'Set a finding to OPEN, NOTED or NOT_RELEVANT', pathParams: ['ledgerId', 'id', 'findingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'list-month-end-closings-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes', summary: 'List the notes of a month-end closing', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'create-month-end-closings-notes': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes', summary: 'Create a note on a month-end closing', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
-
'get-month-end-closings-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Get one note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
-
'update-month-end-closings-notes': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Update a note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
-
'delete-month-end-closings-notes': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Delete a note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
-
'update-month-end-closings-agent-results': { method: 'PUT', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/agent-results', summary: 'Write back a month-end agent run\'s explanations and accrual proposals', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['accounts', 'accruals'] },
|
|
43
|
-
'month-end-closings-agent-run': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/agent-run', summary: 'Compute the month\'s findings and start a month-end agent run', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
44
|
-
'get-fx-rate': { method: 'GET', path: '/v1/ledgers/{id}/fx-rate', summary: 'Resolve the FX rate this ledger would book for a currency on a day, or with purpose=CLOSING the rate its month-end close values a balance at', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
45
|
-
'replace-fx-rate-providers': { method: 'PUT', path: '/v1/ledgers/{id}/fx-rate-providers', summary: 'Replace the list of FX rate providers this ledger asks, leaving the rest of the ledger untouched', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fxRateProviders'] },
|
|
46
|
-
'replace-closing-fx-rate-providers': { method: 'PUT', path: '/v1/ledgers/{id}/closing-fx-rate-providers', summary: 'Replace the list of FX rate providers the month-end close asks, leaving the rest of the ledger untouched', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['closingFxRateProviders'] },
|
|
47
|
-
'list-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/notes', summary: 'Get all notes for a ledger', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
48
|
-
'create-notes': { method: 'POST', path: '/v1/ledgers/{ledgerId}/notes', summary: 'Create a note for a ledger', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
49
|
-
'get-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Get a specific note for a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
50
|
-
'update-notes': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Update a note for a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
51
|
-
'delete-notes': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Delete a note from a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
52
|
-
'list-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/closings', summary: 'List all closings for a ledger, sorted by period end ascending', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
53
|
-
'create-closings': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings', summary: 'Create a new closing in DRAFT status', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
54
|
-
'get-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/closings/{id}', summary: 'Get a single closing by ID', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
55
|
-
'update-closings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/closings/{id}', summary: 'Update closing description', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
56
|
-
'closings-close': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings/{id}/close', summary: 'Transition closing to CLOSED. Computes netPnl from POSTED journals. Valid from DRAFT or REOPENED.', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
57
|
-
'closings-reopen': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings/{id}/reopen', summary: 'Transition closing to REOPENED. netPnl snapshot is preserved. Valid from CLOSED only, and only for the latest CLOSED closing of the ledger.', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
58
|
-
'list-posting-runs': { method: 'GET', path: '/v1/ledgers/{ledgerId}/posting-runs', summary: 'List posting runs for a ledger', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
59
|
-
'create-posting-runs': { method: 'POST', path: '/v1/ledgers/{ledgerId}/posting-runs', summary: 'Post approved journals by date range, IDs or filter', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['journalIds'] },
|
|
60
|
-
'posting-runs': { method: 'GET', path: '/v1/ledgers/{ledgerId}/posting-runs/{id}', summary: 'Get a posting run by ID', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/ledgers', summary: 'List all ledgers', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/ledgers', summary: 'Create a new ledger', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['notes', 'fxRateProviders', 'closingFxRateProviders'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/ledgers/{id}', summary: 'Get a ledger by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/ledgers/{id}', summary: 'Update a ledger', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fxRateProviders', 'closingFxRateProviders'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/ledgers/{id}', summary: 'Delete a ledger', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'list-month-end-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings', summary: 'List the month-end closings of a ledger, newest month first', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'create-month-end-closings': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings', summary: 'Create a DRAFT month-end closing for one calendar month', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'get-month-end-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Get one month-end closing', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'update-month-end-closings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Change the description, postApprovedJournals, accrueOpenTransactions or the open-transaction accounts of a closing', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'delete-month-end-closings': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}', summary: 'Delete a DRAFT closing with its accrual rows, findings, notes and its provisional journal; no other journal is touched', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'month-end-closings-complete': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/complete', summary: 'Complete a DRAFT or REOPENED closing: delete its provisional journal, then book the accrual journal (posted) — with the open transactions\' line pairs when accrueOpenTransactions is on — one reversal journal per reversal date (APPROVED) and the FX revaluation journal (posted) in this ledger, and store the bank and FX rows as they are now; the ledger\'s lockedDate is not changed', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'create-month-end-closings-provisional-booking': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/provisional-booking', summary: 'Book (or book again) the provisional journal of a DRAFT or REOPENED closing: deletes the existing one, then books one APPROVED journal dated the month end with the lines Complete would book there now (accepted accruals, open-transaction pairs, FX revaluation); no reversal, nothing posted, no row marked BOOKED, and none when there is no line. The closing\'s figures ignore it; Complete deletes it first', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'delete-month-end-closings-provisional-booking': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/provisional-booking', summary: 'Delete the provisional journal of a DRAFT or REOPENED closing, if it has one', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'month-end-closings-reopen': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/reopen', summary: 'Reopen a COMPLETED closing: its rows are computed live again and journals keeps naming the last completion\'s journals; no journal and not the ledger\'s lockedDate is changed', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'list-month-end-closings-accruals': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals', summary: 'List the accrual rows of a closing by account code, then title', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'create-month-end-closings-accruals': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals', summary: 'Add a manual accrual row; it starts ACCEPTED', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'update-month-end-closings-accruals': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}', summary: 'Change a PROPOSED or ACCEPTED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'delete-month-end-closings-accruals': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}', summary: 'Delete a PROPOSED, ACCEPTED or DISMISSED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'month-end-closings-accruals-accept': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}/accept', summary: 'Accept a PROPOSED accrual row', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'month-end-closings-accruals-dismiss': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accruals/{accrualId}/dismiss', summary: 'Dismiss a PROPOSED accrual row; the agent does not propose it again', pathParams: ['ledgerId', 'id', 'accrualId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'list-month-end-closings-accrual-accounts': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/accrual-accounts', summary: 'One entry per accrual account of the ledger: the period\'s movement against the average of the three months before, what is accrued, the difference and the month-end instructions; with include=partners also the movement per business partner', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'list-month-end-closings-findings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/findings', summary: 'List the agent\'s findings on a closing: HIGH, MEDIUM, LOW, then by creation time', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'update-month-end-closings-findings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/findings/{findingId}', summary: 'Set a finding to OPEN, NOTED or NOT_RELEVANT', pathParams: ['ledgerId', 'id', 'findingId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'list-month-end-closings-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes', summary: 'List the notes of a month-end closing', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'create-month-end-closings-notes': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes', summary: 'Create a note on a month-end closing', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
40
|
+
'get-month-end-closings-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Get one note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
41
|
+
'update-month-end-closings-notes': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Update a note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
42
|
+
'delete-month-end-closings-notes': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/notes/{noteId}', summary: 'Delete a note of a month-end closing', pathParams: ['ledgerId', 'id', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
43
|
+
'update-month-end-closings-agent-results': { method: 'PUT', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/agent-results', summary: 'Write back a month-end agent run\'s explanations and accrual proposals', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['accounts', 'accruals'], bodyMediaType: '', specParams: [] },
|
|
44
|
+
'month-end-closings-agent-run': { method: 'POST', path: '/v1/ledgers/{ledgerId}/month-end-closings/{id}/agent-run', summary: 'Compute the month\'s findings and start a month-end agent run', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
45
|
+
'get-fx-rate': { method: 'GET', path: '/v1/ledgers/{id}/fx-rate', summary: 'Resolve the FX rate this ledger would book for a currency on a day, or with purpose=CLOSING the rate its month-end close values a balance at', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
46
|
+
'replace-fx-rate-providers': { method: 'PUT', path: '/v1/ledgers/{id}/fx-rate-providers', summary: 'Replace the list of FX rate providers this ledger asks, leaving the rest of the ledger untouched', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['fxRateProviders'], bodyMediaType: '', specParams: [] },
|
|
47
|
+
'replace-closing-fx-rate-providers': { method: 'PUT', path: '/v1/ledgers/{id}/closing-fx-rate-providers', summary: 'Replace the list of FX rate providers the month-end close asks, leaving the rest of the ledger untouched', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['closingFxRateProviders'], bodyMediaType: '', specParams: [] },
|
|
48
|
+
'list-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/notes', summary: 'Get all notes for a ledger', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
49
|
+
'create-notes': { method: 'POST', path: '/v1/ledgers/{ledgerId}/notes', summary: 'Create a note for a ledger', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
50
|
+
'get-notes': { method: 'GET', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Get a specific note for a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
51
|
+
'update-notes': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Update a note for a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
52
|
+
'delete-notes': { method: 'DELETE', path: '/v1/ledgers/{ledgerId}/notes/{noteId}', summary: 'Delete a note from a ledger', pathParams: ['ledgerId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
53
|
+
'list-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/closings', summary: 'List all closings for a ledger, sorted by period end ascending', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
54
|
+
'create-closings': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings', summary: 'Create a new closing in DRAFT status', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
55
|
+
'get-closings': { method: 'GET', path: '/v1/ledgers/{ledgerId}/closings/{id}', summary: 'Get a single closing by ID', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
56
|
+
'update-closings': { method: 'PATCH', path: '/v1/ledgers/{ledgerId}/closings/{id}', summary: 'Update closing description', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
57
|
+
'closings-close': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings/{id}/close', summary: 'Transition closing to CLOSED. Computes netPnl from POSTED journals. Valid from DRAFT or REOPENED. Refused (409) while a DRAFT or APPROVED journal is dated inside the period: a CLOSED period locks every journal in it, so each must be POSTED or CANCELLED first.', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
58
|
+
'closings-reopen': { method: 'POST', path: '/v1/ledgers/{ledgerId}/closings/{id}/reopen', summary: 'Transition closing to REOPENED. netPnl snapshot is preserved. Valid from CLOSED only, and only for the latest CLOSED closing of the ledger.', pathParams: ['ledgerId', 'id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
59
|
+
'list-posting-runs': { method: 'GET', path: '/v1/ledgers/{ledgerId}/posting-runs', summary: 'List posting runs for a ledger', pathParams: ['ledgerId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
60
|
+
'create-posting-runs': { method: 'POST', path: '/v1/ledgers/{ledgerId}/posting-runs', summary: 'Post approved journals by date range, IDs or filter', pathParams: ['ledgerId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['journalIds'], bodyMediaType: '', specParams: [] },
|
|
61
|
+
'posting-runs': { method: 'GET', path: '/v1/ledgers/{ledgerId}/posting-runs/{id}', summary: 'Get a posting run by ID', pathParams: ['ledgerId', 'id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
61
62
|
};
|
|
62
63
|
export default class Ledgers extends Command {
|
|
63
64
|
static description = 'Manage ledgers';
|
|
@@ -79,7 +80,7 @@ export default class Ledgers extends Command {
|
|
|
79
80
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
80
81
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
81
82
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
82
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
83
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
83
84
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
84
85
|
'id': Flags.string({ description: 'Path param: id' }),
|
|
85
86
|
'accrual-id': Flags.string({ description: 'Path param: accrualId' }),
|
|
@@ -214,6 +215,17 @@ export default class Ledgers extends Command {
|
|
|
214
215
|
}
|
|
215
216
|
}
|
|
216
217
|
}
|
|
218
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
219
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
220
|
+
for (const param of endpoint.specParams) {
|
|
221
|
+
const value = flags[param.flag];
|
|
222
|
+
if (value === undefined || value === '') {
|
|
223
|
+
if (param.required)
|
|
224
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
queryParams[param.name] = value;
|
|
228
|
+
}
|
|
217
229
|
let data;
|
|
218
230
|
if (endpoint.isMultipart) {
|
|
219
231
|
if (!flags.file)
|
|
@@ -234,6 +246,25 @@ export default class Ledgers extends Command {
|
|
|
234
246
|
}
|
|
235
247
|
data = form;
|
|
236
248
|
}
|
|
249
|
+
else if (endpoint.bodyMediaType) {
|
|
250
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
251
|
+
// verbatim, under the content type the endpoint asks for.
|
|
252
|
+
if (flags.file) {
|
|
253
|
+
const fsModule = await import('node:fs');
|
|
254
|
+
try {
|
|
255
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
else if (flags.data) {
|
|
262
|
+
data = flags.data;
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
237
268
|
else if (endpoint.hasBody) {
|
|
238
269
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
239
270
|
// input file — skip the read-as-body branch.
|
|
@@ -329,7 +360,7 @@ export default class Ledgers extends Command {
|
|
|
329
360
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
330
361
|
}
|
|
331
362
|
else if (data) {
|
|
332
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
363
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
333
364
|
}
|
|
334
365
|
process.stderr.write('\n');
|
|
335
366
|
}
|
|
@@ -343,6 +374,7 @@ export default class Ledgers extends Command {
|
|
|
343
374
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
344
375
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
345
376
|
data,
|
|
377
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
346
378
|
contextName: flags.context,
|
|
347
379
|
binary: true,
|
|
348
380
|
});
|
|
@@ -368,6 +400,7 @@ export default class Ledgers extends Command {
|
|
|
368
400
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
369
401
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
370
402
|
data,
|
|
403
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
371
404
|
contextName: flags.context,
|
|
372
405
|
binary: true,
|
|
373
406
|
});
|
|
@@ -388,6 +421,7 @@ export default class Ledgers extends Command {
|
|
|
388
421
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
389
422
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
390
423
|
data,
|
|
424
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
391
425
|
contextName: flags.context,
|
|
392
426
|
acceptAny: true,
|
|
393
427
|
});
|
|
@@ -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,24 +12,24 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["get-me-default-tenant", "update-me-default-tenant", "delete-me-default-tenant", "me", "me-all", "list-me-sessions", "delete-me-sessions", "delete-me-sessions-sessionId", "get-me-credentials", "create-me-credentials-otp", "delete-me-credentials-otp", "delete-me-credentials-passkeys", "me-password-change", "me-email-change", "create-me-credentials-passkeys", "me-reauthenticate", "me-security-actions", "self-service-callback"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'get-me-default-tenant': { method: 'GET', path: '/v1/users/me/default-tenant', summary: 'Read my stored default tenant preference', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'update-me-default-tenant': { method: 'PUT', path: '/v1/users/me/default-tenant', summary: 'Set my default tenant for future logins', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'delete-me-default-tenant': { method: 'DELETE', path: '/v1/users/me/default-tenant', summary: 'Clear my default tenant preference', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'me': { method: 'GET', path: '/v1/users/me', summary: 'Read my profile', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'me-all': { method: 'PATCH', path: '/v1/users/me', summary: 'Edit my profile', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'list-me-sessions': { method: 'GET', path: '/v1/users/me/sessions', summary: 'List my active online sessions', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'delete-me-sessions': { method: 'DELETE', path: '/v1/users/me/sessions', summary: 'End all my online sessions', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'delete-me-sessions-sessionId': { method: 'DELETE', path: '/v1/users/me/sessions/{sessionId}', summary: 'End one of my online sessions', pathParams: ['sessionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'get-me-credentials': { method: 'GET', path: '/v1/users/me/credentials', summary: 'Read my credentials and MFA mandate', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'create-me-credentials-otp': { method: 'POST', path: '/v1/users/me/credentials/otp', summary: 'Start hosted OTP enrollment after a recent sign-in', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'delete-me-credentials-otp': { method: 'DELETE', path: '/v1/users/me/credentials/otp', summary: 'Remove my OTP authentication', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'delete-me-credentials-passkeys': { method: 'DELETE', path: '/v1/users/me/credentials/passkeys/{credentialId}', summary: 'Remove one of my passkeys', pathParams: ['credentialId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
26
|
-
'me-password-change': { method: 'POST', path: '/v1/users/me/password-change', summary: 'Start a hosted password change with current password authentication', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'me-email-change': { method: 'POST', path: '/v1/users/me/email-change', summary: 'Start a hosted verified email change', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
28
|
-
'create-me-credentials-passkeys': { method: 'POST', path: '/v1/users/me/credentials/passkeys', summary: 'Start hosted passkey registration after a recent sign-in', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'me-reauthenticate': { method: 'POST', path: '/v1/users/me/reauthenticate', summary: 'Start a fresh browser sign-in for sensitive account operations', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'me-security-actions': { method: 'GET', path: '/v1/users/me/security-actions/{operationId}', summary: 'Read the durable outcome of my hosted security operation', pathParams: ['operationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'self-service-callback': { method: 'GET', path: '/v1/auth/self-service/callback/{operationId}', summary: 'Complete the hosted account action with a bound browser and verified identity', pathParams: ['operationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'get-me-default-tenant': { method: 'GET', path: '/v1/users/me/default-tenant', summary: 'Read my stored default tenant preference', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'update-me-default-tenant': { method: 'PUT', path: '/v1/users/me/default-tenant', summary: 'Set my default tenant for future logins', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'delete-me-default-tenant': { method: 'DELETE', path: '/v1/users/me/default-tenant', summary: 'Clear my default tenant preference', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'me': { method: 'GET', path: '/v1/users/me', summary: 'Read my profile', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'me-all': { method: 'PATCH', path: '/v1/users/me', summary: 'Edit my profile', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'list-me-sessions': { method: 'GET', path: '/v1/users/me/sessions', summary: 'List my active online sessions', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'delete-me-sessions': { method: 'DELETE', path: '/v1/users/me/sessions', summary: 'End all my online sessions', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'delete-me-sessions-sessionId': { method: 'DELETE', path: '/v1/users/me/sessions/{sessionId}', summary: 'End one of my online sessions', pathParams: ['sessionId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'get-me-credentials': { method: 'GET', path: '/v1/users/me/credentials', summary: 'Read my credentials and MFA mandate', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'create-me-credentials-otp': { method: 'POST', path: '/v1/users/me/credentials/otp', summary: 'Start hosted OTP enrollment after a recent sign-in', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'delete-me-credentials-otp': { method: 'DELETE', path: '/v1/users/me/credentials/otp', summary: 'Remove my OTP authentication', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'delete-me-credentials-passkeys': { method: 'DELETE', path: '/v1/users/me/credentials/passkeys/{credentialId}', summary: 'Remove one of my passkeys', pathParams: ['credentialId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'me-password-change': { method: 'POST', path: '/v1/users/me/password-change', summary: 'Start a hosted password change with current password authentication', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'me-email-change': { method: 'POST', path: '/v1/users/me/email-change', summary: 'Start a hosted verified email change', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'create-me-credentials-passkeys': { method: 'POST', path: '/v1/users/me/credentials/passkeys', summary: 'Start hosted passkey registration after a recent sign-in', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'me-reauthenticate': { method: 'POST', path: '/v1/users/me/reauthenticate', summary: 'Start a fresh browser sign-in for sensitive account operations', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'me-security-actions': { method: 'GET', path: '/v1/users/me/security-actions/{operationId}', summary: 'Read the durable outcome of my hosted security operation', pathParams: ['operationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'self-service-callback': { method: 'GET', path: '/v1/auth/self-service/callback/{operationId}', summary: 'Complete the hosted account action with a bound browser and verified identity', pathParams: ['operationId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
33
|
};
|
|
33
34
|
export default class MyAccount extends Command {
|
|
34
35
|
static description = 'Manage my account';
|
|
@@ -43,7 +44,7 @@ export default class MyAccount extends Command {
|
|
|
43
44
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
44
45
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
45
46
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
46
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
47
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
47
48
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
48
49
|
page: Flags.string({ description: 'Page number' }),
|
|
49
50
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -174,6 +175,17 @@ export default class MyAccount extends Command {
|
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
}
|
|
178
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
179
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
180
|
+
for (const param of endpoint.specParams) {
|
|
181
|
+
const value = flags[param.flag];
|
|
182
|
+
if (value === undefined || value === '') {
|
|
183
|
+
if (param.required)
|
|
184
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
queryParams[param.name] = value;
|
|
188
|
+
}
|
|
177
189
|
let data;
|
|
178
190
|
if (endpoint.isMultipart) {
|
|
179
191
|
if (!flags.file)
|
|
@@ -194,6 +206,25 @@ export default class MyAccount extends Command {
|
|
|
194
206
|
}
|
|
195
207
|
data = form;
|
|
196
208
|
}
|
|
209
|
+
else if (endpoint.bodyMediaType) {
|
|
210
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
211
|
+
// verbatim, under the content type the endpoint asks for.
|
|
212
|
+
if (flags.file) {
|
|
213
|
+
const fsModule = await import('node:fs');
|
|
214
|
+
try {
|
|
215
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
else if (flags.data) {
|
|
222
|
+
data = flags.data;
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
197
228
|
else if (endpoint.hasBody) {
|
|
198
229
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
199
230
|
// input file — skip the read-as-body branch.
|
|
@@ -289,7 +320,7 @@ export default class MyAccount extends Command {
|
|
|
289
320
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
290
321
|
}
|
|
291
322
|
else if (data) {
|
|
292
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
323
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
293
324
|
}
|
|
294
325
|
process.stderr.write('\n');
|
|
295
326
|
}
|
|
@@ -303,6 +334,7 @@ export default class MyAccount extends Command {
|
|
|
303
334
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
304
335
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
305
336
|
data,
|
|
337
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
306
338
|
contextName: flags.context,
|
|
307
339
|
binary: true,
|
|
308
340
|
});
|
|
@@ -328,6 +360,7 @@ export default class MyAccount extends Command {
|
|
|
328
360
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
329
361
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
330
362
|
data,
|
|
363
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
331
364
|
contextName: flags.context,
|
|
332
365
|
binary: true,
|
|
333
366
|
});
|
|
@@ -348,6 +381,7 @@ export default class MyAccount extends Command {
|
|
|
348
381
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
349
382
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
350
383
|
data,
|
|
384
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
351
385
|
contextName: flags.context,
|
|
352
386
|
acceptAny: true,
|
|
353
387
|
});
|