@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
|
@@ -464,76 +464,126 @@ export default class VendorInvoices extends Command {
|
|
|
464
464
|
return '';
|
|
465
465
|
};
|
|
466
466
|
const results = [];
|
|
467
|
-
|
|
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:
|
|
535
|
+
data: body,
|
|
473
536
|
contextName: flags.context,
|
|
474
537
|
});
|
|
475
538
|
const id = response.data?.id;
|
|
476
|
-
|
|
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:
|
|
549
|
+
data: body,
|
|
488
550
|
contextName: flags.context,
|
|
489
551
|
});
|
|
490
|
-
|
|
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
|
-
|
|
556
|
+
return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
|
|
495
557
|
}
|
|
496
558
|
}
|
|
497
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
932
|
+
data: body,
|
|
822
933
|
contextName: flags.context,
|
|
823
934
|
});
|
|
824
935
|
const id = response.data?.id;
|
|
825
|
-
|
|
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
|
-
|
|
835
|
-
|
|
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
|
-
|
|
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
|
-
|
|
952
|
+
return { status: 'error', id: existingId, identifier, error: `Update failed: ${msg}` };
|
|
850
953
|
}
|
|
851
954
|
}
|
|
852
|
-
|
|
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
|
-
|
|
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
|
}
|
|
@@ -1050,12 +1142,24 @@ export default class VendorInvoices extends Command {
|
|
|
1050
1142
|
return { cols: flatten ? cols : cols.slice(0, 8), items: items };
|
|
1051
1143
|
}
|
|
1052
1144
|
getValue(row, col) {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1145
|
+
if (!col.includes('.'))
|
|
1146
|
+
return String(row[col] ?? '');
|
|
1147
|
+
const parts = col.split('.');
|
|
1148
|
+
// Walk the dot-path; descending through an array branches into every
|
|
1149
|
+
// element so leaf values get collected from each one. Multiple leaves are
|
|
1150
|
+
// joined with ';' (e.g. dunningReminders.id -> "uuid1;uuid2").
|
|
1151
|
+
const walk = (o, idx) => {
|
|
1152
|
+
if (idx >= parts.length)
|
|
1153
|
+
return [o];
|
|
1154
|
+
if (o == null)
|
|
1155
|
+
return [];
|
|
1156
|
+
if (Array.isArray(o))
|
|
1157
|
+
return o.flatMap(item => walk(item, idx));
|
|
1158
|
+
if (typeof o === 'object')
|
|
1159
|
+
return walk(o[parts[idx]], idx + 1);
|
|
1160
|
+
return [];
|
|
1161
|
+
};
|
|
1162
|
+
return walk(row, 0).filter(v => v !== undefined && v !== null).map(v => String(v)).join(';');
|
|
1059
1163
|
}
|
|
1060
1164
|
printTable(data, fields) {
|
|
1061
1165
|
const { cols, items } = this.getColumns(data, fields);
|