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