@aderis-erp/cli 1.0.10 → 1.0.12

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 (67) hide show
  1. package/README.md +1 -0
  2. package/dist/commands/access-groups.js +178 -86
  3. package/dist/commands/account-transaction-allocations.js +178 -86
  4. package/dist/commands/account-transactions.js +181 -87
  5. package/dist/commands/accounts.js +178 -86
  6. package/dist/commands/agent-runs.d.ts +1 -0
  7. package/dist/commands/agent-runs.js +183 -87
  8. package/dist/commands/audit-log.js +178 -86
  9. package/dist/commands/auth/login.js +4 -3
  10. package/dist/commands/bank-accounts.js +178 -86
  11. package/dist/commands/bank-integrations.js +178 -86
  12. package/dist/commands/business-partners.js +178 -86
  13. package/dist/commands/chat.d.ts +40 -0
  14. package/dist/commands/chat.js +1173 -0
  15. package/dist/commands/config/add.js +4 -3
  16. package/dist/commands/credit-card-accounts.js +178 -86
  17. package/dist/commands/documents.js +178 -86
  18. package/dist/commands/dunning-configs.js +180 -88
  19. package/dist/commands/dunning-reminders.js +178 -86
  20. package/dist/commands/dunning-runs.js +178 -86
  21. package/dist/commands/email-transactions.d.ts +40 -0
  22. package/dist/commands/email-transactions.js +1173 -0
  23. package/dist/commands/employees.js +180 -88
  24. package/dist/commands/entity-configurations.d.ts +40 -0
  25. package/dist/commands/entity-configurations.js +1169 -0
  26. package/dist/commands/event-processor-mappings.js +178 -86
  27. package/dist/commands/files-internal.js +178 -86
  28. package/dist/commands/health.js +178 -86
  29. package/dist/commands/inbox.js +181 -89
  30. package/dist/commands/integrations.js +178 -86
  31. package/dist/commands/item-categories.js +178 -86
  32. package/dist/commands/items.js +178 -86
  33. package/dist/commands/journal-lines.js +178 -86
  34. package/dist/commands/journals.js +178 -86
  35. package/dist/commands/ledgers.js +178 -86
  36. package/dist/commands/office-locations.js +178 -86
  37. package/dist/commands/payment-methods.js +178 -86
  38. package/dist/commands/payment-runs.js +178 -86
  39. package/dist/commands/payment-terms.js +178 -86
  40. package/dist/commands/price-lists.js +178 -86
  41. package/dist/commands/processor-mappings.js +178 -86
  42. package/dist/commands/processors.js +181 -87
  43. package/dist/commands/purchase-order-types.d.ts +40 -0
  44. package/dist/commands/purchase-order-types.js +1178 -0
  45. package/dist/commands/purchase-orders.d.ts +42 -0
  46. package/dist/commands/purchase-orders.js +1192 -0
  47. package/dist/commands/reports.js +178 -86
  48. package/dist/commands/salary-types.js +178 -86
  49. package/dist/commands/sales-invoices.js +187 -93
  50. package/dist/commands/sales-orders.js +186 -93
  51. package/dist/commands/saved-views.js +178 -86
  52. package/dist/commands/tags.js +178 -86
  53. package/dist/commands/tax-codes.js +180 -88
  54. package/dist/commands/tax-matrix.js +178 -86
  55. package/dist/commands/tenants.js +180 -88
  56. package/dist/commands/text-templates.js +178 -86
  57. package/dist/commands/tools.js +178 -86
  58. package/dist/commands/vat-declarations.d.ts +1 -0
  59. package/dist/commands/vat-declarations.js +188 -89
  60. package/dist/commands/vendor-invoices.js +181 -87
  61. package/dist/commands/webhooks.js +178 -86
  62. package/dist/commands/workflows.js +178 -86
  63. package/dist/lib/auth.js +2 -2
  64. package/dist/lib/config.d.ts +1 -1
  65. package/dist/lib/config.js +5 -0
  66. package/oclif.manifest.json +1174 -328
  67. package/package.json +2 -1
@@ -445,76 +445,126 @@ export default class BankAccounts extends Command {
445
445
  return '';
446
446
  };
447
447
  const results = [];
448
- for (const item of items) {
448
+ // Stream output row-by-row so progress is visible during long imports.
449
+ // Pre-compute the identifier column width from the input items so the
450
+ // table stays aligned without buffering all rows.
451
+ // When stdout is piped (IDE terminals, tee, CI), Node switches to async-buffered
452
+ // mode and rows accumulate in the pipe buffer until it fills. Force blocking
453
+ // mode so each \n-terminated write flushes immediately.
454
+ const stdoutHandle = process.stdout._handle;
455
+ if (stdoutHandle?.setBlocking)
456
+ stdoutHandle.setBlocking(true);
457
+ const outputFormat = flags.output || 'table';
458
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
459
+ const useJson = outputFormat === 'json';
460
+ const statusWidth = 8;
461
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
462
+ if (useCsv) {
463
+ this.log('status,identifier,id,error');
464
+ }
465
+ else if (!useJson) {
466
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
467
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
468
+ }
469
+ const emitRow = (r) => {
470
+ if (useJson)
471
+ return;
472
+ if (useCsv) {
473
+ const err = (r.error || '').replace(/"/g, '""');
474
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
475
+ }
476
+ else {
477
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
478
+ }
479
+ };
480
+ // Server-managed fields the API rejects in create/update bodies. Stripped
481
+ // before every request so re-importing a previously-exported payload Just Works.
482
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
483
+ const stripServerFields = (item) => {
484
+ const out = {};
485
+ for (const [k, v] of Object.entries(item)) {
486
+ if (!STRIP_FIELDS.has(k))
487
+ out[k] = v;
488
+ }
489
+ return out;
490
+ };
491
+ const processItem = async (item) => {
449
492
  const identifier = getItemIdentifier(item);
493
+ const body = stripServerFields(item);
494
+ // If the payload carries an id (e.g. re-importing an export), PATCH directly.
495
+ // Fall through to POST only on 404 (so a missing record still gets created).
496
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
497
+ if (itemId) {
498
+ try {
499
+ const updatePath = updateEndpoint.path.replace('{id}', itemId);
500
+ await apiRequest('PATCH', updatePath, {
501
+ data: body,
502
+ contextName: flags.context,
503
+ });
504
+ return { status: 'updated', id: itemId, identifier };
505
+ }
506
+ catch (error) {
507
+ if (!(error instanceof ApiError && error.status === 404)) {
508
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
509
+ return { status: 'error', id: itemId, identifier, error: msg };
510
+ }
511
+ // 404 → record gone, try create below
512
+ }
513
+ }
450
514
  try {
451
- // Try to create
452
515
  const response = await apiRequest('POST', createEndpoint.path, {
453
- data: item,
516
+ data: body,
454
517
  contextName: flags.context,
455
518
  });
456
519
  const id = response.data?.id;
457
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
520
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
458
521
  }
459
522
  catch (error) {
460
523
  if (error instanceof ApiError && error.status === 409) {
461
- // Conflict - try to update existing
462
524
  const errorData = error.data;
463
525
  const existingId = errorData?.existingId;
464
526
  if (existingId) {
465
527
  try {
466
528
  const updatePath = updateEndpoint.path.replace('{id}', existingId);
467
529
  await apiRequest('PATCH', updatePath, {
468
- data: item,
530
+ data: body,
469
531
  contextName: flags.context,
470
532
  });
471
- results.push({ status: 'updated', id: existingId, identifier });
533
+ return { status: 'updated', id: existingId, identifier };
472
534
  }
473
535
  catch (updateError) {
474
536
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
475
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
537
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
476
538
  }
477
539
  }
478
- else {
479
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
480
- }
481
- }
482
- else {
483
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
484
- results.push({ status: 'error', identifier, error: msg });
540
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
485
541
  }
542
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
543
+ return { status: 'error', identifier, error: msg };
486
544
  }
487
- }
545
+ };
546
+ // Worker pool: keep N requests in flight at all times. Rows are emitted as
547
+ // each request resolves (so output order may differ from input order). The
548
+ // summary at the end remains accurate regardless.
549
+ const concurrency = 4;
550
+ const queue = [...items];
551
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
552
+ for (;;) {
553
+ const item = queue.shift();
554
+ if (!item)
555
+ return;
556
+ const r = await processItem(item);
557
+ results.push(r);
558
+ emitRow(r);
559
+ }
560
+ }));
488
561
  // Summary counts
489
562
  const created = results.filter(r => r.status === 'created').length;
490
563
  const updated = results.filter(r => r.status === 'updated').length;
491
564
  const errors = results.filter(r => r.status === 'error');
492
- // Output results based on format (default: table)
493
- const outputFormat = flags.output || 'table';
494
- if (outputFormat === 'json') {
565
+ if (useJson) {
495
566
  this.log(JSON.stringify(results, null, 2));
496
567
  }
497
- else if (outputFormat === 'csv' || flags.csv) {
498
- // CSV output
499
- this.log('status,identifier,id,error');
500
- for (const r of results) {
501
- const err = (r.error || '').replace(/"/g, '""');
502
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
503
- }
504
- }
505
- else {
506
- // Table output (default)
507
- if (results.length > 0) {
508
- const statusWidth = 8;
509
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
510
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
511
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
512
- for (const r of results) {
513
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
514
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
515
- }
516
- }
517
- }
518
568
  // Always show summary at the end
519
569
  this.log('');
520
570
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
@@ -794,80 +844,122 @@ export default class BankAccounts extends Command {
794
844
  return '';
795
845
  };
796
846
  const results = [];
797
- for (const item of items) {
847
+ const stdoutHandle = process.stdout._handle;
848
+ if (stdoutHandle?.setBlocking)
849
+ stdoutHandle.setBlocking(true);
850
+ const outputFormat = flags.output || 'table';
851
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
852
+ const useJson = outputFormat === 'json';
853
+ const statusWidth = 8;
854
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
855
+ if (useCsv) {
856
+ this.log('status,identifier,id,error');
857
+ }
858
+ else if (!useJson) {
859
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
860
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
861
+ }
862
+ const emitRow = (r) => {
863
+ if (useJson)
864
+ return;
865
+ if (useCsv) {
866
+ const err = (r.error || '').replace(/"/g, '""');
867
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
868
+ }
869
+ else {
870
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
871
+ }
872
+ };
873
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
874
+ const stripServerFields = (item) => {
875
+ const out = {};
876
+ for (const [k, v] of Object.entries(item)) {
877
+ if (!STRIP_FIELDS.has(k))
878
+ out[k] = v;
879
+ }
880
+ return out;
881
+ };
882
+ const buildUpdatePath = (existingId) => {
883
+ const firstUpdateParam = updateEndpoint.pathParams[0];
884
+ const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
885
+ let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
886
+ if (nestedIdParam) {
887
+ updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
888
+ }
889
+ return updatePath;
890
+ };
891
+ const processItem = async (item) => {
798
892
  const identifier = getItemIdentifier(item);
893
+ const body = stripServerFields(item);
894
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
895
+ if (itemId) {
896
+ try {
897
+ await apiRequest('PATCH', buildUpdatePath(itemId), {
898
+ data: body,
899
+ contextName: flags.context,
900
+ });
901
+ return { status: 'updated', id: itemId, identifier };
902
+ }
903
+ catch (error) {
904
+ if (!(error instanceof ApiError && error.status === 404)) {
905
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
906
+ return { status: 'error', id: itemId, identifier, error: msg };
907
+ }
908
+ // 404 → fall through and try create
909
+ }
910
+ }
799
911
  try {
800
- // Try to create
801
912
  const response = await apiRequest('POST', basePath, {
802
- data: item,
913
+ data: body,
803
914
  contextName: flags.context,
804
915
  });
805
916
  const id = response.data?.id;
806
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
917
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
807
918
  }
808
919
  catch (error) {
809
920
  if (error instanceof ApiError && error.status === 409) {
810
- // Conflict - try to update existing
811
921
  const errorData = error.data;
812
922
  const existingId = errorData?.existingId || item.id;
813
923
  if (existingId) {
814
924
  try {
815
- // Find the nested ID param name (e.g., 'priceId' for prices)
816
- const firstUpdateParam = updateEndpoint.pathParams[0];
817
- const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
818
- let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
819
- if (nestedIdParam) {
820
- updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
821
- }
822
- await apiRequest('PATCH', updatePath, {
823
- data: item,
925
+ await apiRequest('PATCH', buildUpdatePath(existingId), {
926
+ data: body,
824
927
  contextName: flags.context,
825
928
  });
826
- results.push({ status: 'updated', id: existingId, identifier });
929
+ return { status: 'updated', id: existingId, identifier };
827
930
  }
828
931
  catch (updateError) {
829
932
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
830
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
933
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
831
934
  }
832
935
  }
833
- else {
834
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
835
- }
836
- }
837
- else {
838
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
839
- results.push({ status: 'error', identifier, error: msg });
936
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
840
937
  }
938
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
939
+ return { status: 'error', identifier, error: msg };
841
940
  }
842
- }
941
+ };
942
+ // Worker pool: 4 requests in flight at a time. Rows are emitted as each
943
+ // request resolves so output order may differ from input order.
944
+ const concurrency = 4;
945
+ const queue = [...items];
946
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
947
+ for (;;) {
948
+ const item = queue.shift();
949
+ if (!item)
950
+ return;
951
+ const r = await processItem(item);
952
+ results.push(r);
953
+ emitRow(r);
954
+ }
955
+ }));
843
956
  // Summary counts
844
957
  const created = results.filter(r => r.status === 'created').length;
845
958
  const updated = results.filter(r => r.status === 'updated').length;
846
959
  const errors = results.filter(r => r.status === 'error');
847
- // Output results based on format (default: table)
848
- const outputFormat = flags.output || 'table';
849
- if (outputFormat === 'json') {
960
+ if (useJson) {
850
961
  this.log(JSON.stringify(results, null, 2));
851
962
  }
852
- else if (outputFormat === 'csv' || flags.csv) {
853
- this.log('status,identifier,id,error');
854
- for (const r of results) {
855
- const err = (r.error || '').replace(/"/g, '""');
856
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
857
- }
858
- }
859
- else {
860
- if (results.length > 0) {
861
- const statusWidth = 8;
862
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
863
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
864
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
865
- for (const r of results) {
866
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
867
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
868
- }
869
- }
870
- }
871
963
  this.log('');
872
964
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
873
965
  }