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