@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,14 +12,14 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["pending", "ongoing", "cancelled", "get", "update", "list", "approve", "cancel"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'pending': { method: 'GET', path: '/v1/dunning-reminders/pending', summary: 'Get pending reminders (awaiting approval) with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'ongoing': { method: 'GET', path: '/v1/dunning-reminders/ongoing', summary: 'Get ongoing reminders (pending, sent, or failed) with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'cancelled': { method: 'GET', path: '/v1/dunning-reminders/cancelled', summary: 'Get cancelled reminders with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'get': { method: 'GET', path: '/v1/dunning-reminders/{id}', summary: 'Get a single dunning reminder by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
18
|
-
'update': { method: 'PATCH', path: '/v1/dunning-reminders/{id}', summary: 'Update recipient or action on a dunning reminder', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'list': { method: 'GET', path: '/v1/dunning-reminders', summary: 'Get all dunning reminders with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'approve': { method: 'POST', path: '/v1/dunning-reminders/{reminderId}/approve', summary: 'Approve a dunning reminder for sending', pathParams: ['reminderId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'cancel': { method: 'POST', path: '/v1/dunning-reminders/{reminderId}/cancel', summary: 'Cancel a dunning reminder', pathParams: ['reminderId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'pending': { method: 'GET', path: '/v1/dunning-reminders/pending', summary: 'Get pending reminders (awaiting approval) with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'ongoing': { method: 'GET', path: '/v1/dunning-reminders/ongoing', summary: 'Get ongoing reminders (pending, sent, or failed) with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'cancelled': { method: 'GET', path: '/v1/dunning-reminders/cancelled', summary: 'Get cancelled reminders with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'get': { method: 'GET', path: '/v1/dunning-reminders/{id}', summary: 'Get a single dunning reminder by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'update': { method: 'PATCH', path: '/v1/dunning-reminders/{id}', summary: 'Update recipient or action on a dunning reminder', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'list': { method: 'GET', path: '/v1/dunning-reminders', summary: 'Get all dunning reminders with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'approve': { method: 'POST', path: '/v1/dunning-reminders/{reminderId}/approve', summary: 'Approve a dunning reminder for sending', pathParams: ['reminderId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'cancel': { method: 'POST', path: '/v1/dunning-reminders/{reminderId}/cancel', summary: 'Cancel a dunning reminder', pathParams: ['reminderId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
23
|
};
|
|
23
24
|
export default class DunningReminders extends Command {
|
|
24
25
|
static description = 'Manage dunning reminders';
|
|
@@ -38,7 +39,7 @@ export default class DunningReminders extends Command {
|
|
|
38
39
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
39
40
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
40
41
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
41
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
42
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
42
43
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
43
44
|
page: Flags.string({ description: 'Page number' }),
|
|
44
45
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -169,6 +170,17 @@ export default class DunningReminders extends Command {
|
|
|
169
170
|
}
|
|
170
171
|
}
|
|
171
172
|
}
|
|
173
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
174
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
175
|
+
for (const param of endpoint.specParams) {
|
|
176
|
+
const value = flags[param.flag];
|
|
177
|
+
if (value === undefined || value === '') {
|
|
178
|
+
if (param.required)
|
|
179
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
queryParams[param.name] = value;
|
|
183
|
+
}
|
|
172
184
|
let data;
|
|
173
185
|
if (endpoint.isMultipart) {
|
|
174
186
|
if (!flags.file)
|
|
@@ -189,6 +201,25 @@ export default class DunningReminders extends Command {
|
|
|
189
201
|
}
|
|
190
202
|
data = form;
|
|
191
203
|
}
|
|
204
|
+
else if (endpoint.bodyMediaType) {
|
|
205
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
206
|
+
// verbatim, under the content type the endpoint asks for.
|
|
207
|
+
if (flags.file) {
|
|
208
|
+
const fsModule = await import('node:fs');
|
|
209
|
+
try {
|
|
210
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else if (flags.data) {
|
|
217
|
+
data = flags.data;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
192
223
|
else if (endpoint.hasBody) {
|
|
193
224
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
194
225
|
// input file — skip the read-as-body branch.
|
|
@@ -284,7 +315,7 @@ export default class DunningReminders extends Command {
|
|
|
284
315
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
285
316
|
}
|
|
286
317
|
else if (data) {
|
|
287
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
318
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
288
319
|
}
|
|
289
320
|
process.stderr.write('\n');
|
|
290
321
|
}
|
|
@@ -298,6 +329,7 @@ export default class DunningReminders extends Command {
|
|
|
298
329
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
299
330
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
300
331
|
data,
|
|
332
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
301
333
|
contextName: flags.context,
|
|
302
334
|
binary: true,
|
|
303
335
|
});
|
|
@@ -323,6 +355,7 @@ export default class DunningReminders extends Command {
|
|
|
323
355
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
324
356
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
325
357
|
data,
|
|
358
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
326
359
|
contextName: flags.context,
|
|
327
360
|
binary: true,
|
|
328
361
|
});
|
|
@@ -343,6 +376,7 @@ export default class DunningReminders extends Command {
|
|
|
343
376
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
344
377
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
345
378
|
data,
|
|
379
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
346
380
|
contextName: flags.context,
|
|
347
381
|
acceptAny: true,
|
|
348
382
|
});
|
|
@@ -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 = [...["trigger"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'trigger': { method: 'POST', path: '/v1/dunning-runs/trigger', summary: 'Manually trigger a dunning run', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'trigger': { method: 'POST', path: '/v1/dunning-runs/trigger', summary: 'Manually trigger a dunning run', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
15
16
|
};
|
|
16
17
|
export default class DunningRuns extends Command {
|
|
17
18
|
static description = 'Manage dunning runs';
|
|
@@ -26,7 +27,7 @@ export default class DunningRuns extends Command {
|
|
|
26
27
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
27
28
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
28
29
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
29
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
30
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
30
31
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
31
32
|
page: Flags.string({ description: 'Page number' }),
|
|
32
33
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -157,6 +158,17 @@ export default class DunningRuns extends Command {
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
}
|
|
161
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
162
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
163
|
+
for (const param of endpoint.specParams) {
|
|
164
|
+
const value = flags[param.flag];
|
|
165
|
+
if (value === undefined || value === '') {
|
|
166
|
+
if (param.required)
|
|
167
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
queryParams[param.name] = value;
|
|
171
|
+
}
|
|
160
172
|
let data;
|
|
161
173
|
if (endpoint.isMultipart) {
|
|
162
174
|
if (!flags.file)
|
|
@@ -177,6 +189,25 @@ export default class DunningRuns extends Command {
|
|
|
177
189
|
}
|
|
178
190
|
data = form;
|
|
179
191
|
}
|
|
192
|
+
else if (endpoint.bodyMediaType) {
|
|
193
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
194
|
+
// verbatim, under the content type the endpoint asks for.
|
|
195
|
+
if (flags.file) {
|
|
196
|
+
const fsModule = await import('node:fs');
|
|
197
|
+
try {
|
|
198
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else if (flags.data) {
|
|
205
|
+
data = flags.data;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
180
211
|
else if (endpoint.hasBody) {
|
|
181
212
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
182
213
|
// input file — skip the read-as-body branch.
|
|
@@ -272,7 +303,7 @@ export default class DunningRuns extends Command {
|
|
|
272
303
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
273
304
|
}
|
|
274
305
|
else if (data) {
|
|
275
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
306
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
276
307
|
}
|
|
277
308
|
process.stderr.write('\n');
|
|
278
309
|
}
|
|
@@ -286,6 +317,7 @@ export default class DunningRuns extends Command {
|
|
|
286
317
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
287
318
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
288
319
|
data,
|
|
320
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
289
321
|
contextName: flags.context,
|
|
290
322
|
binary: true,
|
|
291
323
|
});
|
|
@@ -311,6 +343,7 @@ export default class DunningRuns extends Command {
|
|
|
311
343
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
312
344
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
313
345
|
data,
|
|
346
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
314
347
|
contextName: flags.context,
|
|
315
348
|
binary: true,
|
|
316
349
|
});
|
|
@@ -331,6 +364,7 @@ export default class DunningRuns extends Command {
|
|
|
331
364
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
332
365
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
333
366
|
data,
|
|
367
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
334
368
|
contextName: flags.context,
|
|
335
369
|
acceptAny: true,
|
|
336
370
|
});
|
|
@@ -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,9 +12,9 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = [];
|
|
12
13
|
const SUBCOMMANDS = [...["event-webhook", "list", "get"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'event-webhook': { method: 'POST', path: '/v1/email-transactions/event-webhook', summary: 'SendGrid delivery-event webhook (ECDSA signature-verified, no bearer token)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'list': { method: 'GET', path: '/v1/email-transactions', summary: 'List email transactions for the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/email-transactions/{id}', summary: 'Get a single email transaction (404 if not in this tenant)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'event-webhook': { method: 'POST', path: '/v1/email-transactions/event-webhook', summary: 'SendGrid delivery-event webhook (ECDSA signature-verified, no bearer token)', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'list': { method: 'GET', path: '/v1/email-transactions', summary: 'List email transactions for the current tenant', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/email-transactions/{id}', summary: 'Get a single email transaction (404 if not in this tenant)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
17
18
|
};
|
|
18
19
|
export default class EmailTransactions extends Command {
|
|
19
20
|
static description = 'Manage email transactions';
|
|
@@ -32,7 +33,7 @@ export default class EmailTransactions extends Command {
|
|
|
32
33
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
33
34
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
34
35
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
35
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
36
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
36
37
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
37
38
|
page: Flags.string({ description: 'Page number' }),
|
|
38
39
|
limit: Flags.string({ description: 'Items per page' }),
|
|
@@ -163,6 +164,17 @@ export default class EmailTransactions extends Command {
|
|
|
163
164
|
}
|
|
164
165
|
}
|
|
165
166
|
}
|
|
167
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
168
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
169
|
+
for (const param of endpoint.specParams) {
|
|
170
|
+
const value = flags[param.flag];
|
|
171
|
+
if (value === undefined || value === '') {
|
|
172
|
+
if (param.required)
|
|
173
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
queryParams[param.name] = value;
|
|
177
|
+
}
|
|
166
178
|
let data;
|
|
167
179
|
if (endpoint.isMultipart) {
|
|
168
180
|
if (!flags.file)
|
|
@@ -183,6 +195,25 @@ export default class EmailTransactions extends Command {
|
|
|
183
195
|
}
|
|
184
196
|
data = form;
|
|
185
197
|
}
|
|
198
|
+
else if (endpoint.bodyMediaType) {
|
|
199
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
200
|
+
// verbatim, under the content type the endpoint asks for.
|
|
201
|
+
if (flags.file) {
|
|
202
|
+
const fsModule = await import('node:fs');
|
|
203
|
+
try {
|
|
204
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else if (flags.data) {
|
|
211
|
+
data = flags.data;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
186
217
|
else if (endpoint.hasBody) {
|
|
187
218
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
188
219
|
// input file — skip the read-as-body branch.
|
|
@@ -278,7 +309,7 @@ export default class EmailTransactions extends Command {
|
|
|
278
309
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
279
310
|
}
|
|
280
311
|
else if (data) {
|
|
281
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
312
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
282
313
|
}
|
|
283
314
|
process.stderr.write('\n');
|
|
284
315
|
}
|
|
@@ -292,6 +323,7 @@ export default class EmailTransactions extends Command {
|
|
|
292
323
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
293
324
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
294
325
|
data,
|
|
326
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
295
327
|
contextName: flags.context,
|
|
296
328
|
binary: true,
|
|
297
329
|
});
|
|
@@ -317,6 +349,7 @@ export default class EmailTransactions extends Command {
|
|
|
317
349
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
318
350
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
319
351
|
data,
|
|
352
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
320
353
|
contextName: flags.context,
|
|
321
354
|
binary: true,
|
|
322
355
|
});
|
|
@@ -337,6 +370,7 @@ export default class EmailTransactions extends Command {
|
|
|
337
370
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
338
371
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
339
372
|
data,
|
|
373
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
340
374
|
contextName: flags.context,
|
|
341
375
|
acceptAny: true,
|
|
342
376
|
});
|
|
@@ -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,47 +12,47 @@ const SERVER_IMPORTS = [];
|
|
|
11
12
|
const NESTED_UPSERTS = ["salaries", "payments", "notes", "files", "salary-payment-files", "salary-parts"];
|
|
12
13
|
const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "get-salaries", "create-salaries", "get-salaries-salaryId", "update-salaries", "delete-salaries", "get-payments", "create-payments", "get-payments-paymentId", "update-payments", "delete-payments", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download", "list-salary-payment-files", "create-salary-payment-files", "get-salary-payment-files", "update-salary-payment-files", "delete-salary-payment-files", "download-salary-payment-files", "list-salary-parts", "create-salary-parts", "get-salary-parts", "update-salary-parts", "delete-salary-parts", "salary-parts-changes", "update-salary-parts-values", "delete-salary-parts-values", "month-overview"], ...(HAS_UPSERT ? ['upsert'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_UPSERTS.map(n => `upsert-${n}`)];
|
|
13
14
|
const ENDPOINTS = {
|
|
14
|
-
'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
-
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
16
|
-
'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
17
|
-
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'] },
|
|
18
|
-
'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
19
|
-
'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
20
|
-
'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
21
|
-
'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
22
|
-
'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
23
|
-
'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
24
|
-
'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
25
|
-
'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
26
|
-
'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
27
|
-
'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'] },
|
|
28
|
-
'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
29
|
-
'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
30
|
-
'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
31
|
-
'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
32
|
-
'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
33
|
-
'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
34
|
-
'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
35
|
-
'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
36
|
-
'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
37
|
-
'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
38
|
-
'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
39
|
-
'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
40
|
-
'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
41
|
-
'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
42
|
-
'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
43
|
-
'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
44
|
-
'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
45
|
-
'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
46
|
-
'list-salary-parts': { method: 'GET', path: '/v1/employees/{employeeId}/salary-parts', summary: 'List an employee\'s salary parts with their monthly values', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
47
|
-
'create-salary-parts': { method: 'POST', path: '/v1/employees/{employeeId}/salary-parts', summary: 'Create a salary part', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
48
|
-
'get-salary-parts': { method: 'GET', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Get a salary part with its monthly values', pathParams: ['employeeId', 'salaryPartId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
49
|
-
'update-salary-parts': { method: 'PATCH', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Change a salary part; an earlier end date removes later values', pathParams: ['employeeId', 'salaryPartId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
50
|
-
'delete-salary-parts': { method: 'DELETE', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Delete a salary part and its monthly values', pathParams: ['employeeId', 'salaryPartId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
51
|
-
'salary-parts-changes': { method: 'POST', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/changes', summary: 'Change a fixed salary part from a date', pathParams: ['employeeId', 'salaryPartId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
52
|
-
'update-salary-parts-values': { method: 'PUT', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/values/{month}', summary: 'Create or replace the value of one month of a variable salary part', pathParams: ['employeeId', 'salaryPartId', 'month'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
53
|
-
'delete-salary-parts-values': { method: 'DELETE', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/values/{month}', summary: 'Delete the value of one month of a variable salary part', pathParams: ['employeeId', 'salaryPartId', 'month'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
54
|
-
'month-overview': { method: 'GET', path: '/v1/salary-parts/month-overview', summary: 'Variable salary parts of all employees in one month', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [] },
|
|
15
|
+
'list': { method: 'GET', path: '/v1/employees', summary: 'Get all employees with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
16
|
+
'create': { method: 'POST', path: '/v1/employees', summary: 'Create a new employee', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
17
|
+
'get': { method: 'GET', path: '/v1/employees/{id}', summary: 'Get an employee by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
18
|
+
'update': { method: 'PATCH', path: '/v1/employees/{id}', summary: 'Update an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['beneficiaries', 'children', 'salaries', 'files', 'notes', 'tagIds', 'tagCodes'], bodyMediaType: '', specParams: [] },
|
|
19
|
+
'delete': { method: 'DELETE', path: '/v1/employees/{id}', summary: 'Delete an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
20
|
+
'get-salaries': { method: 'GET', path: '/v1/employees/{id}/salaries', summary: 'Get all salaries for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
21
|
+
'create-salaries': { method: 'POST', path: '/v1/employees/{id}/salaries', summary: 'Add a salary configuration to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
22
|
+
'get-salaries-salaryId': { method: 'GET', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Get a specific salary by ID', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
23
|
+
'update-salaries': { method: 'PATCH', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Update a salary configuration', pathParams: ['id', 'salaryId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
24
|
+
'delete-salaries': { method: 'DELETE', path: '/v1/employees/{id}/salaries/{salaryId}', summary: 'Delete a salary configuration', pathParams: ['id', 'salaryId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
25
|
+
'get-payments': { method: 'GET', path: '/v1/employees/{id}/payments', summary: 'Get all payments for an employee', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
26
|
+
'create-payments': { method: 'POST', path: '/v1/employees/{id}/payments', summary: 'Add a payment to an employee', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'], bodyMediaType: '', specParams: [] },
|
|
27
|
+
'get-payments-paymentId': { method: 'GET', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Get a specific payment by ID', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
28
|
+
'update-payments': { method: 'PATCH', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Update a payment', pathParams: ['id', 'paymentId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: ['salaryComponents', 'files'], bodyMediaType: '', specParams: [] },
|
|
29
|
+
'delete-payments': { method: 'DELETE', path: '/v1/employees/{id}/payments/{paymentId}', summary: 'Delete a payment', pathParams: ['id', 'paymentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
30
|
+
'list-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes', summary: 'Get all notes for an employee', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
31
|
+
'create-notes': { method: 'POST', path: '/v1/employees/{employeeId}/notes', summary: 'Create a note for an employee', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
32
|
+
'get-notes': { method: 'GET', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Get a specific note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
33
|
+
'update-notes': { method: 'PATCH', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Update a note for an employee', pathParams: ['employeeId', 'noteId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
34
|
+
'delete-notes': { method: 'DELETE', path: '/v1/employees/{employeeId}/notes/{noteId}', summary: 'Delete a note from an employee', pathParams: ['employeeId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
35
|
+
'list-files': { method: 'GET', path: '/v1/employees/{parentId}/files', summary: 'List file attachments for a employee', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
36
|
+
'create-files': { method: 'POST', path: '/v1/employees/{parentId}/files', summary: 'Upload a file attachment to a employee', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
37
|
+
'get-files': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Get a file attachment for a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
38
|
+
'update-files': { method: 'PATCH', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a employee', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
39
|
+
'delete-files': { method: 'DELETE', path: '/v1/employees/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
40
|
+
'files-download': { method: 'GET', path: '/v1/employees/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a employee', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
41
|
+
'list-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files', summary: 'List file attachments for a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
42
|
+
'create-salary-payment-files': { method: 'POST', path: '/v1/salary-payments/{parentId}/files', summary: 'Upload a file attachment to a salary payment', pathParams: ['parentId'], hasBody: false, isMultipart: true, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
43
|
+
'get-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Get a file attachment for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
44
|
+
'update-salary-payment-files': { method: 'PATCH', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Update file attachment metadata for a salary payment', pathParams: ['parentId', 'fileId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
45
|
+
'delete-salary-payment-files': { method: 'DELETE', path: '/v1/salary-payments/{parentId}/files/{fileId}', summary: 'Delete a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
46
|
+
'download-salary-payment-files': { method: 'GET', path: '/v1/salary-payments/{parentId}/files/{fileId}/download', summary: 'Download a file attachment from a salary payment', pathParams: ['parentId', 'fileId'], hasBody: false, isMultipart: false, isBinaryResponse: true, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
47
|
+
'list-salary-parts': { method: 'GET', path: '/v1/employees/{employeeId}/salary-parts', summary: 'List an employee\'s salary parts with their monthly values', pathParams: ['employeeId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
48
|
+
'create-salary-parts': { method: 'POST', path: '/v1/employees/{employeeId}/salary-parts', summary: 'Create a salary part', pathParams: ['employeeId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
49
|
+
'get-salary-parts': { method: 'GET', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Get a salary part with its monthly values', pathParams: ['employeeId', 'salaryPartId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
50
|
+
'update-salary-parts': { method: 'PATCH', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Change a salary part; an earlier end date removes later values', pathParams: ['employeeId', 'salaryPartId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
51
|
+
'delete-salary-parts': { method: 'DELETE', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}', summary: 'Delete a salary part and its monthly values', pathParams: ['employeeId', 'salaryPartId'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
52
|
+
'salary-parts-changes': { method: 'POST', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/changes', summary: 'Change a fixed salary part from a date', pathParams: ['employeeId', 'salaryPartId'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
53
|
+
'update-salary-parts-values': { method: 'PUT', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/values/{month}', summary: 'Create or replace the value of one month of a variable salary part', pathParams: ['employeeId', 'salaryPartId', 'month'], hasBody: true, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
54
|
+
'delete-salary-parts-values': { method: 'DELETE', path: '/v1/employees/{employeeId}/salary-parts/{salaryPartId}/values/{month}', summary: 'Delete the value of one month of a variable salary part', pathParams: ['employeeId', 'salaryPartId', 'month'], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
55
|
+
'month-overview': { method: 'GET', path: '/v1/salary-parts/month-overview', summary: 'Variable salary parts of all employees in one month', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, hasBinaryVariant: false, bodyArrayFields: [], bodyMediaType: '', specParams: [] },
|
|
55
56
|
};
|
|
56
57
|
export default class Employees extends Command {
|
|
57
58
|
static description = 'Manage employees';
|
|
@@ -73,7 +74,7 @@ export default class Employees extends Command {
|
|
|
73
74
|
table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
|
|
74
75
|
csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
|
|
75
76
|
data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
|
|
76
|
-
file: Flags.string({ char: 'f', description: 'Read request body from file' }),
|
|
77
|
+
file: Flags.string({ char: 'f', description: 'Read request body from file', parse: async (input) => resolveUserPath(input) }),
|
|
77
78
|
set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
|
|
78
79
|
'salary-id': Flags.string({ description: 'Path param: salaryId' }),
|
|
79
80
|
'payment-id': Flags.string({ description: 'Path param: paymentId' }),
|
|
@@ -210,6 +211,17 @@ export default class Employees extends Command {
|
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
}
|
|
214
|
+
// Flags generated from this endpoint's own parameters. Raw-body endpoints
|
|
215
|
+
// have them: their body is not JSON, so --set cannot carry a value there.
|
|
216
|
+
for (const param of endpoint.specParams) {
|
|
217
|
+
const value = flags[param.flag];
|
|
218
|
+
if (value === undefined || value === '') {
|
|
219
|
+
if (param.required)
|
|
220
|
+
this.error(`Missing required flag: --${param.flag}`);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
queryParams[param.name] = value;
|
|
224
|
+
}
|
|
213
225
|
let data;
|
|
214
226
|
if (endpoint.isMultipart) {
|
|
215
227
|
if (!flags.file)
|
|
@@ -230,6 +242,25 @@ export default class Employees extends Command {
|
|
|
230
242
|
}
|
|
231
243
|
data = form;
|
|
232
244
|
}
|
|
245
|
+
else if (endpoint.bodyMediaType) {
|
|
246
|
+
// The body is not JSON (today only application/x-ndjson): it is sent
|
|
247
|
+
// verbatim, under the content type the endpoint asks for.
|
|
248
|
+
if (flags.file) {
|
|
249
|
+
const fsModule = await import('node:fs');
|
|
250
|
+
try {
|
|
251
|
+
data = fsModule.readFileSync(flags.file, 'utf-8');
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
this.error(`Failed to read file: ${flags.file}`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (flags.data) {
|
|
258
|
+
data = flags.data;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
this.error(`This endpoint takes its body as ${endpoint.bodyMediaType}. Pass the file with -f / --file, or the text with --data.`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
233
264
|
else if (endpoint.hasBody) {
|
|
234
265
|
// For binary-response endpoints, --file is the output path, not a JSON
|
|
235
266
|
// input file — skip the read-as-body branch.
|
|
@@ -325,7 +356,7 @@ export default class Employees extends Command {
|
|
|
325
356
|
process.stderr.write(`Body: [multipart/form-data file upload]\n`);
|
|
326
357
|
}
|
|
327
358
|
else if (data) {
|
|
328
|
-
process.stderr.write(`Body: ${JSON.stringify(data, null, 2)}\n`);
|
|
359
|
+
process.stderr.write(`Body: ${typeof data === 'string' ? data : JSON.stringify(data, null, 2)}\n`);
|
|
329
360
|
}
|
|
330
361
|
process.stderr.write('\n');
|
|
331
362
|
}
|
|
@@ -339,6 +370,7 @@ export default class Employees extends Command {
|
|
|
339
370
|
const binResponse = await apiRequest(endpoint.method, apiPath, {
|
|
340
371
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
341
372
|
data,
|
|
373
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
342
374
|
contextName: flags.context,
|
|
343
375
|
binary: true,
|
|
344
376
|
});
|
|
@@ -364,6 +396,7 @@ export default class Employees extends Command {
|
|
|
364
396
|
const raw = await apiRequest(endpoint.method, apiPath, {
|
|
365
397
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
366
398
|
data,
|
|
399
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
367
400
|
contextName: flags.context,
|
|
368
401
|
binary: true,
|
|
369
402
|
});
|
|
@@ -384,6 +417,7 @@ export default class Employees extends Command {
|
|
|
384
417
|
response = await apiRequest(endpoint.method, apiPath, {
|
|
385
418
|
params: Object.keys(queryParams).length > 0 ? queryParams : undefined,
|
|
386
419
|
data,
|
|
420
|
+
contentType: endpoint.bodyMediaType || undefined,
|
|
387
421
|
contextName: flags.context,
|
|
388
422
|
acceptAny: true,
|
|
389
423
|
});
|