@aderis-erp/cli 1.0.10 → 1.0.11

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