@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
@@ -446,76 +446,126 @@ export default class BankIntegrations extends Command {
446
446
  return '';
447
447
  };
448
448
  const results = [];
449
- for (const item of items) {
449
+ // Stream output row-by-row so progress is visible during long imports.
450
+ // Pre-compute the identifier column width from the input items so the
451
+ // table stays aligned without buffering all rows.
452
+ // When stdout is piped (IDE terminals, tee, CI), Node switches to async-buffered
453
+ // mode and rows accumulate in the pipe buffer until it fills. Force blocking
454
+ // mode so each \n-terminated write flushes immediately.
455
+ const stdoutHandle = process.stdout._handle;
456
+ if (stdoutHandle?.setBlocking)
457
+ stdoutHandle.setBlocking(true);
458
+ const outputFormat = flags.output || 'table';
459
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
460
+ const useJson = outputFormat === 'json';
461
+ const statusWidth = 8;
462
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
463
+ if (useCsv) {
464
+ this.log('status,identifier,id,error');
465
+ }
466
+ else if (!useJson) {
467
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
468
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
469
+ }
470
+ const emitRow = (r) => {
471
+ if (useJson)
472
+ return;
473
+ if (useCsv) {
474
+ const err = (r.error || '').replace(/"/g, '""');
475
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
476
+ }
477
+ else {
478
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
479
+ }
480
+ };
481
+ // Server-managed fields the API rejects in create/update bodies. Stripped
482
+ // before every request so re-importing a previously-exported payload Just Works.
483
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
484
+ const stripServerFields = (item) => {
485
+ const out = {};
486
+ for (const [k, v] of Object.entries(item)) {
487
+ if (!STRIP_FIELDS.has(k))
488
+ out[k] = v;
489
+ }
490
+ return out;
491
+ };
492
+ const processItem = async (item) => {
450
493
  const identifier = getItemIdentifier(item);
494
+ const body = stripServerFields(item);
495
+ // If the payload carries an id (e.g. re-importing an export), PATCH directly.
496
+ // Fall through to POST only on 404 (so a missing record still gets created).
497
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
498
+ if (itemId) {
499
+ try {
500
+ const updatePath = updateEndpoint.path.replace('{id}', itemId);
501
+ await apiRequest('PATCH', updatePath, {
502
+ data: body,
503
+ contextName: flags.context,
504
+ });
505
+ return { status: 'updated', id: itemId, identifier };
506
+ }
507
+ catch (error) {
508
+ if (!(error instanceof ApiError && error.status === 404)) {
509
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
510
+ return { status: 'error', id: itemId, identifier, error: msg };
511
+ }
512
+ // 404 → record gone, try create below
513
+ }
514
+ }
451
515
  try {
452
- // Try to create
453
516
  const response = await apiRequest('POST', createEndpoint.path, {
454
- data: item,
517
+ data: body,
455
518
  contextName: flags.context,
456
519
  });
457
520
  const id = response.data?.id;
458
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
521
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
459
522
  }
460
523
  catch (error) {
461
524
  if (error instanceof ApiError && error.status === 409) {
462
- // Conflict - try to update existing
463
525
  const errorData = error.data;
464
526
  const existingId = errorData?.existingId;
465
527
  if (existingId) {
466
528
  try {
467
529
  const updatePath = updateEndpoint.path.replace('{id}', existingId);
468
530
  await apiRequest('PATCH', updatePath, {
469
- data: item,
531
+ data: body,
470
532
  contextName: flags.context,
471
533
  });
472
- results.push({ status: 'updated', id: existingId, identifier });
534
+ return { status: 'updated', id: existingId, identifier };
473
535
  }
474
536
  catch (updateError) {
475
537
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
476
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
538
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
477
539
  }
478
540
  }
479
- else {
480
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
481
- }
482
- }
483
- else {
484
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
485
- results.push({ status: 'error', identifier, error: msg });
541
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
486
542
  }
543
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
544
+ return { status: 'error', identifier, error: msg };
487
545
  }
488
- }
546
+ };
547
+ // Worker pool: keep N requests in flight at all times. Rows are emitted as
548
+ // each request resolves (so output order may differ from input order). The
549
+ // summary at the end remains accurate regardless.
550
+ const concurrency = 4;
551
+ const queue = [...items];
552
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
553
+ for (;;) {
554
+ const item = queue.shift();
555
+ if (!item)
556
+ return;
557
+ const r = await processItem(item);
558
+ results.push(r);
559
+ emitRow(r);
560
+ }
561
+ }));
489
562
  // Summary counts
490
563
  const created = results.filter(r => r.status === 'created').length;
491
564
  const updated = results.filter(r => r.status === 'updated').length;
492
565
  const errors = results.filter(r => r.status === 'error');
493
- // Output results based on format (default: table)
494
- const outputFormat = flags.output || 'table';
495
- if (outputFormat === 'json') {
566
+ if (useJson) {
496
567
  this.log(JSON.stringify(results, null, 2));
497
568
  }
498
- else if (outputFormat === 'csv' || flags.csv) {
499
- // CSV output
500
- this.log('status,identifier,id,error');
501
- for (const r of results) {
502
- const err = (r.error || '').replace(/"/g, '""');
503
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
504
- }
505
- }
506
- else {
507
- // Table output (default)
508
- if (results.length > 0) {
509
- const statusWidth = 8;
510
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
511
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
512
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
513
- for (const r of results) {
514
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
515
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
516
- }
517
- }
518
- }
519
569
  // Always show summary at the end
520
570
  this.log('');
521
571
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
@@ -795,80 +845,122 @@ export default class BankIntegrations extends Command {
795
845
  return '';
796
846
  };
797
847
  const results = [];
798
- for (const item of items) {
848
+ const stdoutHandle = process.stdout._handle;
849
+ if (stdoutHandle?.setBlocking)
850
+ stdoutHandle.setBlocking(true);
851
+ const outputFormat = flags.output || 'table';
852
+ const useCsv = outputFormat === 'csv' || Boolean(flags.csv);
853
+ const useJson = outputFormat === 'json';
854
+ const statusWidth = 8;
855
+ const identifierWidth = Math.max(10, ...items.map(i => getItemIdentifier(i).length));
856
+ if (useCsv) {
857
+ this.log('status,identifier,id,error');
858
+ }
859
+ else if (!useJson) {
860
+ this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
861
+ this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
862
+ }
863
+ const emitRow = (r) => {
864
+ if (useJson)
865
+ return;
866
+ if (useCsv) {
867
+ const err = (r.error || '').replace(/"/g, '""');
868
+ this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
869
+ }
870
+ else {
871
+ this.log(`${r.status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
872
+ }
873
+ };
874
+ const STRIP_FIELDS = new Set(['id', '_type', 'tenantId', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy']);
875
+ const stripServerFields = (item) => {
876
+ const out = {};
877
+ for (const [k, v] of Object.entries(item)) {
878
+ if (!STRIP_FIELDS.has(k))
879
+ out[k] = v;
880
+ }
881
+ return out;
882
+ };
883
+ const buildUpdatePath = (existingId) => {
884
+ const firstUpdateParam = updateEndpoint.pathParams[0];
885
+ const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
886
+ let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
887
+ if (nestedIdParam) {
888
+ updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
889
+ }
890
+ return updatePath;
891
+ };
892
+ const processItem = async (item) => {
799
893
  const identifier = getItemIdentifier(item);
894
+ const body = stripServerFields(item);
895
+ const itemId = typeof item.id === 'string' ? item.id : undefined;
896
+ if (itemId) {
897
+ try {
898
+ await apiRequest('PATCH', buildUpdatePath(itemId), {
899
+ data: body,
900
+ contextName: flags.context,
901
+ });
902
+ return { status: 'updated', id: itemId, identifier };
903
+ }
904
+ catch (error) {
905
+ if (!(error instanceof ApiError && error.status === 404)) {
906
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
907
+ return { status: 'error', id: itemId, identifier, error: msg };
908
+ }
909
+ // 404 → fall through and try create
910
+ }
911
+ }
800
912
  try {
801
- // Try to create
802
913
  const response = await apiRequest('POST', basePath, {
803
- data: item,
914
+ data: body,
804
915
  contextName: flags.context,
805
916
  });
806
917
  const id = response.data?.id;
807
- results.push({ status: 'created', id: id ? String(id) : undefined, identifier });
918
+ return { status: 'created', id: id ? String(id) : undefined, identifier };
808
919
  }
809
920
  catch (error) {
810
921
  if (error instanceof ApiError && error.status === 409) {
811
- // Conflict - try to update existing
812
922
  const errorData = error.data;
813
923
  const existingId = errorData?.existingId || item.id;
814
924
  if (existingId) {
815
925
  try {
816
- // Find the nested ID param name (e.g., 'priceId' for prices)
817
- const firstUpdateParam = updateEndpoint.pathParams[0];
818
- const nestedIdParam = updateEndpoint.pathParams.find((p, i) => i > 0);
819
- let updatePath = updateEndpoint.path.replace(`{${firstUpdateParam}}`, parentId);
820
- if (nestedIdParam) {
821
- updatePath = updatePath.replace(`{${nestedIdParam}}`, existingId);
822
- }
823
- await apiRequest('PATCH', updatePath, {
824
- data: item,
926
+ await apiRequest('PATCH', buildUpdatePath(existingId), {
927
+ data: body,
825
928
  contextName: flags.context,
826
929
  });
827
- results.push({ status: 'updated', id: existingId, identifier });
930
+ return { status: 'updated', id: existingId, identifier };
828
931
  }
829
932
  catch (updateError) {
830
933
  const msg = updateError instanceof ApiError ? updateError.message : String(updateError);
831
- results.push({ status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` });
934
+ return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
832
935
  }
833
936
  }
834
- else {
835
- results.push({ status: 'error', identifier, error: 'Conflict but no existingId returned' });
836
- }
837
- }
838
- else {
839
- const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
840
- results.push({ status: 'error', identifier, error: msg });
937
+ return { status: 'error', identifier, error: 'Conflict but no existingId returned' };
841
938
  }
939
+ const msg = error instanceof ApiError ? `(${error.status}) ${error.message}` : String(error);
940
+ return { status: 'error', identifier, error: msg };
842
941
  }
843
- }
942
+ };
943
+ // Worker pool: 4 requests in flight at a time. Rows are emitted as each
944
+ // request resolves so output order may differ from input order.
945
+ const concurrency = 4;
946
+ const queue = [...items];
947
+ await Promise.all(Array.from({ length: Math.min(concurrency, queue.length) }, async () => {
948
+ for (;;) {
949
+ const item = queue.shift();
950
+ if (!item)
951
+ return;
952
+ const r = await processItem(item);
953
+ results.push(r);
954
+ emitRow(r);
955
+ }
956
+ }));
844
957
  // Summary counts
845
958
  const created = results.filter(r => r.status === 'created').length;
846
959
  const updated = results.filter(r => r.status === 'updated').length;
847
960
  const errors = results.filter(r => r.status === 'error');
848
- // Output results based on format (default: table)
849
- const outputFormat = flags.output || 'table';
850
- if (outputFormat === 'json') {
961
+ if (useJson) {
851
962
  this.log(JSON.stringify(results, null, 2));
852
963
  }
853
- else if (outputFormat === 'csv' || flags.csv) {
854
- this.log('status,identifier,id,error');
855
- for (const r of results) {
856
- const err = (r.error || '').replace(/"/g, '""');
857
- this.log(`${r.status},${r.identifier || ''},${r.id || ''},"${err}"`);
858
- }
859
- }
860
- else {
861
- if (results.length > 0) {
862
- const statusWidth = 8;
863
- const identifierWidth = Math.max(10, ...results.map(r => (r.identifier || '').length));
864
- this.log(`${'status'.padEnd(statusWidth)} ${'identifier'.padEnd(identifierWidth)} error`);
865
- this.log(`${'-'.repeat(statusWidth)} ${'-'.repeat(identifierWidth)} ${'-'.repeat(50)}`);
866
- for (const r of results) {
867
- const status = r.status === 'created' ? 'created' : r.status === 'updated' ? 'updated' : 'error';
868
- this.log(`${status.padEnd(statusWidth)} ${(r.identifier || '').padEnd(identifierWidth)} ${r.error || ''}`);
869
- }
870
- }
871
- }
872
964
  this.log('');
873
965
  this.log(`Summary: ${created} created, ${updated} updated, ${errors.length} failed`);
874
966
  }