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