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