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