@aderis-erp/cli 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/commands/access-groups.js +21 -21
  2. package/dist/commands/account-transaction-allocations.js +21 -21
  3. package/dist/commands/account-transactions.js +23 -23
  4. package/dist/commands/accounts.js +23 -23
  5. package/dist/commands/agent-platform.js +23 -22
  6. package/dist/commands/analytics.d.ts +40 -0
  7. package/dist/commands/{documents.js → analytics.js} +33 -43
  8. package/dist/commands/audit-log.js +24 -24
  9. package/dist/commands/auth/login.js +11 -2
  10. package/dist/commands/auth/logout.d.ts +2 -0
  11. package/dist/commands/auth/logout.js +19 -6
  12. package/dist/commands/auth/status.js +26 -12
  13. package/dist/commands/auth/tenant.js +12 -3
  14. package/dist/commands/auth.js +32 -17
  15. package/dist/commands/bank-accounts.js +21 -21
  16. package/dist/commands/bank-integrations.js +21 -21
  17. package/dist/commands/business-partners.js +29 -26
  18. package/dist/commands/chat.js +21 -21
  19. package/dist/commands/config/add.d.ts +9 -0
  20. package/dist/commands/config/add.js +64 -2
  21. package/dist/commands/config/current.js +9 -4
  22. package/dist/commands/config/list.js +9 -4
  23. package/dist/commands/config/set-api-key.d.ts +10 -0
  24. package/dist/commands/config/set-api-key.js +49 -0
  25. package/dist/commands/config/use.js +3 -4
  26. package/dist/commands/credit-card-accounts.js +21 -21
  27. package/dist/commands/delivery-notes.js +28 -25
  28. package/dist/commands/dunning-configs.js +21 -21
  29. package/dist/commands/dunning-reminders.js +21 -21
  30. package/dist/commands/dunning-runs.js +21 -21
  31. package/dist/commands/email-transactions.js +21 -21
  32. package/dist/commands/employees.js +23 -23
  33. package/dist/commands/entity-configurations.js +21 -21
  34. package/dist/commands/event-processor-mappings.js +21 -21
  35. package/dist/commands/{documents.d.ts → files.d.ts} +1 -1
  36. package/dist/commands/{files-internal.js → files.js} +39 -33
  37. package/dist/commands/health.js +21 -21
  38. package/dist/commands/inbox.d.ts +1 -0
  39. package/dist/commands/inbox.js +25 -23
  40. package/dist/commands/integrations.js +21 -21
  41. package/dist/commands/item-categories.js +21 -21
  42. package/dist/commands/items.js +23 -23
  43. package/dist/commands/journal-lines.js +21 -21
  44. package/dist/commands/journals.js +27 -24
  45. package/dist/commands/ledgers.js +25 -22
  46. package/dist/commands/office-locations.js +21 -21
  47. package/dist/commands/payment-methods.js +21 -21
  48. package/dist/commands/payment-runs.js +23 -22
  49. package/dist/commands/payment-terms.js +21 -21
  50. package/dist/commands/payments.js +21 -21
  51. package/dist/commands/price-lists.js +21 -21
  52. package/dist/commands/processor-mappings.js +21 -21
  53. package/dist/commands/processors.js +21 -21
  54. package/dist/commands/purchase-order-types.js +21 -21
  55. package/dist/commands/purchase-orders.d.ts +1 -0
  56. package/dist/commands/purchase-orders.js +32 -25
  57. package/dist/commands/reports.js +21 -21
  58. package/dist/commands/salary-types.js +21 -21
  59. package/dist/commands/sales-invoices.js +33 -31
  60. package/dist/commands/sales-orders.js +23 -23
  61. package/dist/commands/saved-views.js +21 -21
  62. package/dist/commands/scheduled-processor-mappings.d.ts +40 -0
  63. package/dist/commands/scheduled-processor-mappings.js +1178 -0
  64. package/dist/commands/schedules.js +21 -21
  65. package/dist/commands/switch.js +10 -3
  66. package/dist/commands/{files-internal.d.ts → tag-configurations.d.ts} +1 -1
  67. package/dist/commands/tag-configurations.js +1178 -0
  68. package/dist/commands/tags.js +21 -21
  69. package/dist/commands/tax-codes.js +21 -21
  70. package/dist/commands/tax-matrix.js +21 -21
  71. package/dist/commands/tenants.js +23 -23
  72. package/dist/commands/text-templates.js +21 -21
  73. package/dist/commands/tools.js +21 -21
  74. package/dist/commands/vat-declarations.js +21 -21
  75. package/dist/commands/vendor-invoices.js +25 -25
  76. package/dist/commands/webhooks.js +21 -21
  77. package/dist/commands/workflows.js +21 -21
  78. package/dist/lib/api-client.d.ts +8 -0
  79. package/dist/lib/api-client.js +31 -6
  80. package/dist/lib/auth.d.ts +8 -0
  81. package/dist/lib/auth.js +51 -7
  82. package/dist/lib/base-api-command.js +6 -4
  83. package/dist/lib/config.d.ts +31 -1
  84. package/dist/lib/config.js +31 -0
  85. package/oclif.manifest.json +1099 -443
  86. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
2
+ import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
+ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = false;
6
6
  const HAS_EXPORT = false;
@@ -23,7 +23,7 @@ export default class Integrations extends Command {
23
23
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
24
24
  };
25
25
  static flags = {
26
- context: Flags.string({ char: 'c', description: 'Context to use' }),
26
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
27
27
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
28
28
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
29
29
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -35,7 +35,7 @@ export default class Integrations extends Command {
35
35
  limit: Flags.string({ description: 'Items per page' }),
36
36
  include: Flags.string({ description: 'Relations to include' }),
37
37
  search: Flags.string({ description: 'Search term' }),
38
- 'sort-by': Flags.string({ description: 'Sort field' }),
38
+ 'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
39
39
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
40
40
  query: Flags.string({ description: 'Additional query params as JSON' }),
41
41
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -96,9 +96,9 @@ export default class Integrations extends Command {
96
96
  }
97
97
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
98
98
  if (!context)
99
- this.error('No context configured. Run: aderis auth login --new');
100
- if (!context.tokens)
101
- this.error('Not logged in. Run: aderis auth login');
99
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
100
+ if (!hasCredentials(context))
101
+ this.error(missingCredentialsMessage(context));
102
102
  const queryParams = {};
103
103
  if (flags.page)
104
104
  queryParams.page = flags.page;
@@ -109,7 +109,7 @@ export default class Integrations extends Command {
109
109
  if (flags.search)
110
110
  queryParams.search = flags.search;
111
111
  if (flags['sort-by'])
112
- queryParams.sortBy = flags['sort-by'];
112
+ queryParams.sortBy = normalizeSortBy(flags['sort-by']);
113
113
  if (flags.query) {
114
114
  try {
115
115
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -341,9 +341,9 @@ export default class Integrations extends Command {
341
341
  async runImport(flags) {
342
342
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
343
343
  if (!context)
344
- this.error('No context configured. Run: aderis auth login --new');
345
- if (!context.tokens)
346
- this.error('Not logged in. Run: aderis auth login');
344
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
345
+ if (!hasCredentials(context))
346
+ this.error(missingCredentialsMessage(context));
347
347
  // Get data from file, --data, or --set flags
348
348
  let items = [];
349
349
  if (flags.file) {
@@ -553,9 +553,9 @@ export default class Integrations extends Command {
553
553
  async runExport(flags) {
554
554
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
555
555
  if (!context)
556
- this.error('No context configured. Run: aderis auth login --new');
557
- if (!context.tokens)
558
- this.error('Not logged in. Run: aderis auth login');
556
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
557
+ if (!hasCredentials(context))
558
+ this.error(missingCredentialsMessage(context));
559
559
  const listEndpoint = ENDPOINTS['list'];
560
560
  if (!listEndpoint)
561
561
  this.error('Export requires a list endpoint');
@@ -568,7 +568,7 @@ export default class Integrations extends Command {
568
568
  if (flags.search)
569
569
  baseParams.search = flags.search;
570
570
  if (flags['sort-by'])
571
- baseParams.sortBy = flags['sort-by'];
571
+ baseParams.sortBy = normalizeSortBy(flags['sort-by']);
572
572
  if (flags.include)
573
573
  baseParams.include = flags.include;
574
574
  if (flags.query) {
@@ -647,9 +647,9 @@ export default class Integrations extends Command {
647
647
  async runCamt053Import(flags) {
648
648
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
649
649
  if (!context)
650
- this.error('No context configured. Run: aderis auth login --new');
651
- if (!context.tokens)
652
- this.error('Not logged in. Run: aderis auth login');
650
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
651
+ if (!hasCredentials(context))
652
+ this.error(missingCredentialsMessage(context));
653
653
  if (!flags.file) {
654
654
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
655
655
  }
@@ -737,9 +737,9 @@ export default class Integrations extends Command {
737
737
  }
738
738
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
739
739
  if (!context)
740
- this.error('No context configured. Run: aderis auth login --new');
741
- if (!context.tokens)
742
- this.error('Not logged in. Run: aderis auth login');
740
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
741
+ if (!hasCredentials(context))
742
+ this.error(missingCredentialsMessage(context));
743
743
  // Get data from file, --data, or --set flags
744
744
  let items = [];
745
745
  if (flags.file) {
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
2
+ import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
+ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
@@ -29,7 +29,7 @@ export default class ItemCategories extends Command {
29
29
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
30
30
  };
31
31
  static flags = {
32
- context: Flags.string({ char: 'c', description: 'Context to use' }),
32
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
33
33
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
34
34
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
35
35
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -40,7 +40,7 @@ export default class ItemCategories extends Command {
40
40
  limit: Flags.string({ description: 'Items per page' }),
41
41
  include: Flags.string({ description: 'Relations to include' }),
42
42
  search: Flags.string({ description: 'Search term' }),
43
- 'sort-by': Flags.string({ description: 'Sort field' }),
43
+ 'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
44
44
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
45
45
  query: Flags.string({ description: 'Additional query params as JSON' }),
46
46
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -101,9 +101,9 @@ export default class ItemCategories extends Command {
101
101
  }
102
102
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
103
103
  if (!context)
104
- this.error('No context configured. Run: aderis auth login --new');
105
- if (!context.tokens)
106
- this.error('Not logged in. Run: aderis auth login');
104
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
105
+ if (!hasCredentials(context))
106
+ this.error(missingCredentialsMessage(context));
107
107
  const queryParams = {};
108
108
  if (flags.page)
109
109
  queryParams.page = flags.page;
@@ -114,7 +114,7 @@ export default class ItemCategories extends Command {
114
114
  if (flags.search)
115
115
  queryParams.search = flags.search;
116
116
  if (flags['sort-by'])
117
- queryParams.sortBy = flags['sort-by'];
117
+ queryParams.sortBy = normalizeSortBy(flags['sort-by']);
118
118
  if (flags.query) {
119
119
  try {
120
120
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -346,9 +346,9 @@ export default class ItemCategories extends Command {
346
346
  async runImport(flags) {
347
347
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
348
348
  if (!context)
349
- this.error('No context configured. Run: aderis auth login --new');
350
- if (!context.tokens)
351
- this.error('Not logged in. Run: aderis auth login');
349
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
350
+ if (!hasCredentials(context))
351
+ this.error(missingCredentialsMessage(context));
352
352
  // Get data from file, --data, or --set flags
353
353
  let items = [];
354
354
  if (flags.file) {
@@ -558,9 +558,9 @@ export default class ItemCategories extends Command {
558
558
  async runExport(flags) {
559
559
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
560
560
  if (!context)
561
- this.error('No context configured. Run: aderis auth login --new');
562
- if (!context.tokens)
563
- this.error('Not logged in. Run: aderis auth login');
561
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
562
+ if (!hasCredentials(context))
563
+ this.error(missingCredentialsMessage(context));
564
564
  const listEndpoint = ENDPOINTS['list'];
565
565
  if (!listEndpoint)
566
566
  this.error('Export requires a list endpoint');
@@ -573,7 +573,7 @@ export default class ItemCategories extends Command {
573
573
  if (flags.search)
574
574
  baseParams.search = flags.search;
575
575
  if (flags['sort-by'])
576
- baseParams.sortBy = flags['sort-by'];
576
+ baseParams.sortBy = normalizeSortBy(flags['sort-by']);
577
577
  if (flags.include)
578
578
  baseParams.include = flags.include;
579
579
  if (flags.query) {
@@ -652,9 +652,9 @@ export default class ItemCategories extends Command {
652
652
  async runCamt053Import(flags) {
653
653
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
654
654
  if (!context)
655
- this.error('No context configured. Run: aderis auth login --new');
656
- if (!context.tokens)
657
- this.error('Not logged in. Run: aderis auth login');
655
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
656
+ if (!hasCredentials(context))
657
+ this.error(missingCredentialsMessage(context));
658
658
  if (!flags.file) {
659
659
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
660
660
  }
@@ -742,9 +742,9 @@ export default class ItemCategories extends Command {
742
742
  }
743
743
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
744
744
  if (!context)
745
- this.error('No context configured. Run: aderis auth login --new');
746
- if (!context.tokens)
747
- this.error('Not logged in. Run: aderis auth login');
745
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
746
+ if (!hasCredentials(context))
747
+ this.error(missingCredentialsMessage(context));
748
748
  // Get data from file, --data, or --set flags
749
749
  let items = [];
750
750
  if (flags.file) {
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
2
+ import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
+ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
@@ -9,9 +9,9 @@ const NESTED_IMPORTS = [];
9
9
  const SUBCOMMANDS = [...["list", "create", "get", "update", "delete"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'list': { method: 'GET', path: '/v1/items', summary: 'Get all items with pagination', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds'] },
12
+ 'create': { method: 'POST', path: '/v1/items', summary: 'Create a new item', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
13
13
  'get': { method: 'GET', path: '/v1/items/{id}', summary: 'Get an item by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds'] },
14
+ 'update': { method: 'PATCH', path: '/v1/items/{id}', summary: 'Update an item', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'tagCodes'] },
15
15
  'delete': { method: 'DELETE', path: '/v1/items/{id}', summary: 'Delete an item', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
16
  };
17
17
  export default class Items extends Command {
@@ -29,7 +29,7 @@ export default class Items extends Command {
29
29
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
30
30
  };
31
31
  static flags = {
32
- context: Flags.string({ char: 'c', description: 'Context to use' }),
32
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
33
33
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
34
34
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
35
35
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -40,7 +40,7 @@ export default class Items extends Command {
40
40
  limit: Flags.string({ description: 'Items per page' }),
41
41
  include: Flags.string({ description: 'Relations to include' }),
42
42
  search: Flags.string({ description: 'Search term' }),
43
- 'sort-by': Flags.string({ description: 'Sort field' }),
43
+ 'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
44
44
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
45
45
  query: Flags.string({ description: 'Additional query params as JSON' }),
46
46
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -101,9 +101,9 @@ export default class Items extends Command {
101
101
  }
102
102
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
103
103
  if (!context)
104
- this.error('No context configured. Run: aderis auth login --new');
105
- if (!context.tokens)
106
- this.error('Not logged in. Run: aderis auth login');
104
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
105
+ if (!hasCredentials(context))
106
+ this.error(missingCredentialsMessage(context));
107
107
  const queryParams = {};
108
108
  if (flags.page)
109
109
  queryParams.page = flags.page;
@@ -114,7 +114,7 @@ export default class Items extends Command {
114
114
  if (flags.search)
115
115
  queryParams.search = flags.search;
116
116
  if (flags['sort-by'])
117
- queryParams.sortBy = flags['sort-by'];
117
+ queryParams.sortBy = normalizeSortBy(flags['sort-by']);
118
118
  if (flags.query) {
119
119
  try {
120
120
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -346,9 +346,9 @@ export default class Items extends Command {
346
346
  async runImport(flags) {
347
347
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
348
348
  if (!context)
349
- this.error('No context configured. Run: aderis auth login --new');
350
- if (!context.tokens)
351
- this.error('Not logged in. Run: aderis auth login');
349
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
350
+ if (!hasCredentials(context))
351
+ this.error(missingCredentialsMessage(context));
352
352
  // Get data from file, --data, or --set flags
353
353
  let items = [];
354
354
  if (flags.file) {
@@ -558,9 +558,9 @@ export default class Items extends Command {
558
558
  async runExport(flags) {
559
559
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
560
560
  if (!context)
561
- this.error('No context configured. Run: aderis auth login --new');
562
- if (!context.tokens)
563
- this.error('Not logged in. Run: aderis auth login');
561
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
562
+ if (!hasCredentials(context))
563
+ this.error(missingCredentialsMessage(context));
564
564
  const listEndpoint = ENDPOINTS['list'];
565
565
  if (!listEndpoint)
566
566
  this.error('Export requires a list endpoint');
@@ -573,7 +573,7 @@ export default class Items extends Command {
573
573
  if (flags.search)
574
574
  baseParams.search = flags.search;
575
575
  if (flags['sort-by'])
576
- baseParams.sortBy = flags['sort-by'];
576
+ baseParams.sortBy = normalizeSortBy(flags['sort-by']);
577
577
  if (flags.include)
578
578
  baseParams.include = flags.include;
579
579
  if (flags.query) {
@@ -652,9 +652,9 @@ export default class Items extends Command {
652
652
  async runCamt053Import(flags) {
653
653
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
654
654
  if (!context)
655
- this.error('No context configured. Run: aderis auth login --new');
656
- if (!context.tokens)
657
- this.error('Not logged in. Run: aderis auth login');
655
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
656
+ if (!hasCredentials(context))
657
+ this.error(missingCredentialsMessage(context));
658
658
  if (!flags.file) {
659
659
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
660
660
  }
@@ -742,9 +742,9 @@ export default class Items extends Command {
742
742
  }
743
743
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
744
744
  if (!context)
745
- this.error('No context configured. Run: aderis auth login --new');
746
- if (!context.tokens)
747
- this.error('Not logged in. Run: aderis auth login');
745
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
746
+ if (!hasCredentials(context))
747
+ this.error(missingCredentialsMessage(context));
748
748
  // Get data from file, --data, or --set flags
749
749
  let items = [];
750
750
  if (flags.file) {
@@ -1,6 +1,6 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
2
+ import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
+ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = false;
6
6
  const HAS_EXPORT = true;
@@ -21,7 +21,7 @@ export default class JournalLines extends Command {
21
21
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
22
22
  };
23
23
  static flags = {
24
- context: Flags.string({ char: 'c', description: 'Context to use' }),
24
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
25
25
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
26
26
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
27
27
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -32,7 +32,7 @@ export default class JournalLines extends Command {
32
32
  limit: Flags.string({ description: 'Items per page' }),
33
33
  include: Flags.string({ description: 'Relations to include' }),
34
34
  search: Flags.string({ description: 'Search term' }),
35
- 'sort-by': Flags.string({ description: 'Sort field' }),
35
+ 'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
36
36
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
37
37
  query: Flags.string({ description: 'Additional query params as JSON' }),
38
38
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -93,9 +93,9 @@ export default class JournalLines extends Command {
93
93
  }
94
94
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
95
95
  if (!context)
96
- this.error('No context configured. Run: aderis auth login --new');
97
- if (!context.tokens)
98
- this.error('Not logged in. Run: aderis auth login');
96
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
97
+ if (!hasCredentials(context))
98
+ this.error(missingCredentialsMessage(context));
99
99
  const queryParams = {};
100
100
  if (flags.page)
101
101
  queryParams.page = flags.page;
@@ -106,7 +106,7 @@ export default class JournalLines extends Command {
106
106
  if (flags.search)
107
107
  queryParams.search = flags.search;
108
108
  if (flags['sort-by'])
109
- queryParams.sortBy = flags['sort-by'];
109
+ queryParams.sortBy = normalizeSortBy(flags['sort-by']);
110
110
  if (flags.query) {
111
111
  try {
112
112
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -338,9 +338,9 @@ export default class JournalLines extends Command {
338
338
  async runImport(flags) {
339
339
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
340
340
  if (!context)
341
- this.error('No context configured. Run: aderis auth login --new');
342
- if (!context.tokens)
343
- this.error('Not logged in. Run: aderis auth login');
341
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
342
+ if (!hasCredentials(context))
343
+ this.error(missingCredentialsMessage(context));
344
344
  // Get data from file, --data, or --set flags
345
345
  let items = [];
346
346
  if (flags.file) {
@@ -550,9 +550,9 @@ export default class JournalLines extends Command {
550
550
  async runExport(flags) {
551
551
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
552
552
  if (!context)
553
- this.error('No context configured. Run: aderis auth login --new');
554
- if (!context.tokens)
555
- this.error('Not logged in. Run: aderis auth login');
553
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
554
+ if (!hasCredentials(context))
555
+ this.error(missingCredentialsMessage(context));
556
556
  const listEndpoint = ENDPOINTS['list'];
557
557
  if (!listEndpoint)
558
558
  this.error('Export requires a list endpoint');
@@ -565,7 +565,7 @@ export default class JournalLines extends Command {
565
565
  if (flags.search)
566
566
  baseParams.search = flags.search;
567
567
  if (flags['sort-by'])
568
- baseParams.sortBy = flags['sort-by'];
568
+ baseParams.sortBy = normalizeSortBy(flags['sort-by']);
569
569
  if (flags.include)
570
570
  baseParams.include = flags.include;
571
571
  if (flags.query) {
@@ -644,9 +644,9 @@ export default class JournalLines extends Command {
644
644
  async runCamt053Import(flags) {
645
645
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
646
646
  if (!context)
647
- this.error('No context configured. Run: aderis auth login --new');
648
- if (!context.tokens)
649
- this.error('Not logged in. Run: aderis auth login');
647
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
648
+ if (!hasCredentials(context))
649
+ this.error(missingCredentialsMessage(context));
650
650
  if (!flags.file) {
651
651
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
652
652
  }
@@ -734,9 +734,9 @@ export default class JournalLines extends Command {
734
734
  }
735
735
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
736
736
  if (!context)
737
- this.error('No context configured. Run: aderis auth login --new');
738
- if (!context.tokens)
739
- this.error('Not logged in. Run: aderis auth login');
737
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
738
+ if (!hasCredentials(context))
739
+ this.error(missingCredentialsMessage(context));
740
740
  // Get data from file, --data, or --set flags
741
741
  let items = [];
742
742
  if (flags.file) {
@@ -1,21 +1,24 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
- import { apiRequest, ApiError } from '../lib/api-client.js';
3
- import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
2
+ import { apiRequest, ApiError, normalizeSortBy } from '../lib/api-client.js';
3
+ import { getCurrentContext, getContext, getBaseUrls, hasCredentials, missingCredentialsMessage } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = ["notes", "files"];
9
- const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "post", "approve", "cancel", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "post", "approve", "cancel", "reverse", "get-deferrals", "create-deferrals", "list-notes", "create-notes", "get-notes", "update-notes", "delete-notes", "list-files", "create-files", "get-files", "update-files", "delete-files", "files-download"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'list': { method: 'GET', path: '/v1/journals', summary: 'List all journals', pathParams: [], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
12
- 'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'lines', 'notes'] },
12
+ 'create': { method: 'POST', path: '/v1/journals', summary: 'Create a new journal (with embedded lines)', pathParams: [], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['lines', 'notes'] },
13
13
  'get': { method: 'GET', path: '/v1/journals/{id}', summary: 'Get a journal by ID', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
14
- 'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['tagIds', 'lines'] },
14
+ 'update': { method: 'PATCH', path: '/v1/journals/{id}', summary: 'Update a journal (with embedded lines upsert)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['lines'] },
15
15
  'delete': { method: 'DELETE', path: '/v1/journals/{id}', summary: 'Delete a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
16
16
  'post': { method: 'POST', path: '/v1/journals/{id}/post', summary: 'Post journal (finalize)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
17
17
  'approve': { method: 'POST', path: '/v1/journals/{id}/approve', summary: 'Approve a journal (transitions DRAFT to APPROVED)', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
18
18
  'cancel': { method: 'POST', path: '/v1/journals/{id}/cancel', summary: 'Cancel a journal', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
19
+ 'reverse': { method: 'POST', path: '/v1/journals/{id}/reverse', summary: 'Reverse a posted journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
20
+ 'get-deferrals': { method: 'GET', path: '/v1/journals/{id}/deferrals', summary: 'List the deferral schedules of a journal', pathParams: ['id'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
21
+ 'create-deferrals': { method: 'POST', path: '/v1/journals/{id}/deferrals', summary: 'Create deferral schedules for one line of a journal (manual trigger)', pathParams: ['id'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: ['periods'] },
19
22
  'list-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes', summary: 'Get all notes for a journal', pathParams: ['journalId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
20
23
  'create-notes': { method: 'POST', path: '/v1/journals/{journalId}/notes', summary: 'Create a note for a journal', pathParams: ['journalId'], hasBody: true, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
21
24
  'get-notes': { method: 'GET', path: '/v1/journals/{journalId}/notes/{noteId}', summary: 'Get a specific note for a journal', pathParams: ['journalId', 'noteId'], hasBody: false, isMultipart: false, isBinaryResponse: false, bodyArrayFields: [] },
@@ -43,7 +46,7 @@ export default class Journals extends Command {
43
46
  id: Args.string({ description: 'Resource ID (for get, update, delete operations)', required: false }),
44
47
  };
45
48
  static flags = {
46
- context: Flags.string({ char: 'c', description: 'Context to use' }),
49
+ context: Flags.string({ char: 'c', aliases: ['config'], env: 'ADERIS_CONTEXT', description: 'Context to use for this command, overriding the current context (alias: --config)' }),
47
50
  output: Flags.string({ char: 'o', description: 'Output format (default: table for import, json for other commands)', options: ['json', 'table', 'csv'] }),
48
51
  table: Flags.boolean({ char: 't', description: 'Output as table (shortcut for --output table)' }),
49
52
  csv: Flags.boolean({ description: 'Output as CSV (shortcut for --output csv)' }),
@@ -56,7 +59,7 @@ export default class Journals extends Command {
56
59
  limit: Flags.string({ description: 'Items per page' }),
57
60
  include: Flags.string({ description: 'Relations to include' }),
58
61
  search: Flags.string({ description: 'Search term' }),
59
- 'sort-by': Flags.string({ description: 'Sort field' }),
62
+ 'sort-by': Flags.string({ description: 'Sort field(s), comma-separated. Direction (:ASC/:DESC) is optional; date-like fields default to DESC, others to ASC.' }),
60
63
  filter: Flags.string({ description: 'Filter (e.g. --filter status=ACTIVE). Operators: in:A,B, like:%, gt:, lt:, null:', multiple: true }),
61
64
  query: Flags.string({ description: 'Additional query params as JSON' }),
62
65
  fields: Flags.string({ description: 'Comma-separated list of fields to show (e.g. --fields=id,name,status)' }),
@@ -117,9 +120,9 @@ export default class Journals extends Command {
117
120
  }
118
121
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
119
122
  if (!context)
120
- this.error('No context configured. Run: aderis auth login --new');
121
- if (!context.tokens)
122
- this.error('Not logged in. Run: aderis auth login');
123
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
124
+ if (!hasCredentials(context))
125
+ this.error(missingCredentialsMessage(context));
123
126
  const queryParams = {};
124
127
  if (flags.page)
125
128
  queryParams.page = flags.page;
@@ -130,7 +133,7 @@ export default class Journals extends Command {
130
133
  if (flags.search)
131
134
  queryParams.search = flags.search;
132
135
  if (flags['sort-by'])
133
- queryParams.sortBy = flags['sort-by'];
136
+ queryParams.sortBy = normalizeSortBy(flags['sort-by']);
134
137
  if (flags.query) {
135
138
  try {
136
139
  Object.assign(queryParams, JSON.parse(flags.query));
@@ -362,9 +365,9 @@ export default class Journals extends Command {
362
365
  async runImport(flags) {
363
366
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
364
367
  if (!context)
365
- this.error('No context configured. Run: aderis auth login --new');
366
- if (!context.tokens)
367
- this.error('Not logged in. Run: aderis auth login');
368
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
369
+ if (!hasCredentials(context))
370
+ this.error(missingCredentialsMessage(context));
368
371
  // Get data from file, --data, or --set flags
369
372
  let items = [];
370
373
  if (flags.file) {
@@ -574,9 +577,9 @@ export default class Journals extends Command {
574
577
  async runExport(flags) {
575
578
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
576
579
  if (!context)
577
- this.error('No context configured. Run: aderis auth login --new');
578
- if (!context.tokens)
579
- this.error('Not logged in. Run: aderis auth login');
580
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
581
+ if (!hasCredentials(context))
582
+ this.error(missingCredentialsMessage(context));
580
583
  const listEndpoint = ENDPOINTS['list'];
581
584
  if (!listEndpoint)
582
585
  this.error('Export requires a list endpoint');
@@ -589,7 +592,7 @@ export default class Journals extends Command {
589
592
  if (flags.search)
590
593
  baseParams.search = flags.search;
591
594
  if (flags['sort-by'])
592
- baseParams.sortBy = flags['sort-by'];
595
+ baseParams.sortBy = normalizeSortBy(flags['sort-by']);
593
596
  if (flags.include)
594
597
  baseParams.include = flags.include;
595
598
  if (flags.query) {
@@ -668,9 +671,9 @@ export default class Journals extends Command {
668
671
  async runCamt053Import(flags) {
669
672
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
670
673
  if (!context)
671
- this.error('No context configured. Run: aderis auth login --new');
672
- if (!context.tokens)
673
- this.error('Not logged in. Run: aderis auth login');
674
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
675
+ if (!hasCredentials(context))
676
+ this.error(missingCredentialsMessage(context));
674
677
  if (!flags.file) {
675
678
  this.error('CAMT.053 import requires --file (-f) flag with path to XML file');
676
679
  }
@@ -758,9 +761,9 @@ export default class Journals extends Command {
758
761
  }
759
762
  const context = flags.context ? getContext(flags.context) : getCurrentContext();
760
763
  if (!context)
761
- this.error('No context configured. Run: aderis auth login --new');
762
- if (!context.tokens)
763
- this.error('Not logged in. Run: aderis auth login');
764
+ this.error(flags.context ? `Context "${flags.context}" not found. List contexts with: aderis config list` : 'No context configured. Run: aderis auth login --new');
765
+ if (!hasCredentials(context))
766
+ this.error(missingCredentialsMessage(context));
764
767
  // Get data from file, --data, or --set flags
765
768
  let items = [];
766
769
  if (flags.file) {