@aderis-erp/cli 1.0.9 → 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.
- package/README.md +1 -0
- package/dist/commands/access-groups.js +196 -92
- package/dist/commands/account-transaction-allocations.js +196 -92
- package/dist/commands/account-transactions.js +199 -93
- package/dist/commands/accounts.js +196 -92
- package/dist/commands/agent-runs.d.ts +1 -0
- package/dist/commands/agent-runs.js +201 -93
- package/dist/commands/audit-log.js +196 -92
- package/dist/commands/auth/login.js +4 -3
- package/dist/commands/bank-accounts.js +196 -92
- package/dist/commands/bank-integrations.js +196 -92
- package/dist/commands/business-partners.js +196 -92
- package/dist/commands/config/add.js +4 -3
- package/dist/commands/credit-card-accounts.js +196 -92
- package/dist/commands/documents.js +196 -92
- package/dist/commands/dunning-configs.js +198 -94
- package/dist/commands/dunning-reminders.js +196 -92
- package/dist/commands/dunning-runs.js +196 -92
- package/dist/commands/employees.js +198 -94
- package/dist/commands/entity-configurations.d.ts +40 -0
- package/dist/commands/entity-configurations.js +1169 -0
- package/dist/commands/event-processor-mappings.js +196 -92
- package/dist/commands/files-internal.js +196 -92
- package/dist/commands/health.js +196 -92
- package/dist/commands/inbox.js +199 -95
- package/dist/commands/integrations.js +196 -92
- package/dist/commands/item-categories.js +196 -92
- package/dist/commands/items.js +196 -92
- package/dist/commands/journal-lines.js +196 -92
- package/dist/commands/journals.js +196 -92
- package/dist/commands/ledgers.js +196 -92
- package/dist/commands/office-locations.js +196 -92
- package/dist/commands/payment-methods.js +196 -92
- package/dist/commands/payment-runs.js +196 -92
- package/dist/commands/payment-terms.js +196 -92
- package/dist/commands/price-lists.js +196 -92
- package/dist/commands/processor-mappings.js +196 -92
- package/dist/commands/processors.js +199 -93
- package/dist/commands/purchase-order-types.d.ts +40 -0
- package/dist/commands/purchase-order-types.js +1178 -0
- package/dist/commands/purchase-orders.d.ts +40 -0
- package/dist/commands/purchase-orders.js +1182 -0
- package/dist/commands/reports.js +196 -92
- package/dist/commands/salary-types.js +196 -92
- package/dist/commands/sales-invoices.js +196 -92
- package/dist/commands/sales-orders.js +200 -95
- package/dist/commands/saved-views.js +196 -92
- package/dist/commands/tags.js +196 -92
- package/dist/commands/tax-codes.js +196 -92
- package/dist/commands/tax-matrix.js +196 -92
- package/dist/commands/tenants.js +196 -92
- package/dist/commands/text-templates.js +196 -92
- package/dist/commands/tools.js +196 -92
- package/dist/commands/vat-declarations.d.ts +1 -0
- package/dist/commands/vat-declarations.js +206 -95
- package/dist/commands/vendor-invoices.js +196 -92
- package/dist/commands/webhooks.js +196 -92
- package/dist/commands/workflows.js +196 -92
- package/dist/lib/auth.js +2 -2
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.js +5 -0
- package/oclif.manifest.json +516 -9
- package/package.json +1 -1
|
@@ -446,76 +446,126 @@ export default class BankIntegrations extends Command {
|
|
|
446
446
|
return '';
|
|
447
447
|
};
|
|
448
448
|
const results = [];
|
|
449
|
-
|
|
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:
|
|
517
|
+
data: body,
|
|
455
518
|
contextName: flags.context,
|
|
456
519
|
});
|
|
457
520
|
const id = response.data?.id;
|
|
458
|
-
|
|
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:
|
|
531
|
+
data: body,
|
|
470
532
|
contextName: flags.context,
|
|
471
533
|
});
|
|
472
|
-
|
|
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
|
-
|
|
538
|
+
return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
|
|
477
539
|
}
|
|
478
540
|
}
|
|
479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
914
|
+
data: body,
|
|
804
915
|
contextName: flags.context,
|
|
805
916
|
});
|
|
806
917
|
const id = response.data?.id;
|
|
807
|
-
|
|
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
|
-
|
|
817
|
-
|
|
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
|
-
|
|
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
|
-
|
|
934
|
+
return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
|
|
832
935
|
}
|
|
833
936
|
}
|
|
834
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -1032,12 +1124,24 @@ export default class BankIntegrations extends Command {
|
|
|
1032
1124
|
return { cols: flatten ? cols : cols.slice(0, 8), items: items };
|
|
1033
1125
|
}
|
|
1034
1126
|
getValue(row, col) {
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1127
|
+
if (!col.includes('.'))
|
|
1128
|
+
return String(row[col] ?? '');
|
|
1129
|
+
const parts = col.split('.');
|
|
1130
|
+
// Walk the dot-path; descending through an array branches into every
|
|
1131
|
+
// element so leaf values get collected from each one. Multiple leaves are
|
|
1132
|
+
// joined with ';' (e.g. dunningReminders.id -> "uuid1;uuid2").
|
|
1133
|
+
const walk = (o, idx) => {
|
|
1134
|
+
if (idx >= parts.length)
|
|
1135
|
+
return [o];
|
|
1136
|
+
if (o == null)
|
|
1137
|
+
return [];
|
|
1138
|
+
if (Array.isArray(o))
|
|
1139
|
+
return o.flatMap(item => walk(item, idx));
|
|
1140
|
+
if (typeof o === 'object')
|
|
1141
|
+
return walk(o[parts[idx]], idx + 1);
|
|
1142
|
+
return [];
|
|
1143
|
+
};
|
|
1144
|
+
return walk(row, 0).filter(v => v !== undefined && v !== null).map(v => String(v)).join(';');
|
|
1041
1145
|
}
|
|
1042
1146
|
printTable(data, fields) {
|
|
1043
1147
|
const { cols, items } = this.getColumns(data, fields);
|