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