@aderis-erp/cli 1.0.1 → 1.0.3

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/access-groups.js +36 -22
  3. package/dist/commands/account-transactions.js +30 -18
  4. package/dist/commands/accounts.js +30 -18
  5. package/dist/commands/agent-runs.js +33 -21
  6. package/dist/commands/{processing-logs.d.ts → async-endpoints-internal.d.ts} +2 -2
  7. package/dist/commands/{processing-logs.js → async-endpoints-internal.js} +39 -28
  8. package/dist/commands/audit-log.js +30 -18
  9. package/dist/commands/auth/tenant.d.ts +1 -0
  10. package/dist/commands/auth/tenant.js +23 -7
  11. package/dist/commands/bank-accounts.js +30 -18
  12. package/dist/commands/bank-integrations.d.ts +2 -0
  13. package/dist/commands/bank-integrations.js +41 -19
  14. package/dist/commands/business-partners---contacts.js +30 -18
  15. package/dist/commands/business-partners.js +30 -18
  16. package/dist/commands/credit-card-accounts.js +30 -18
  17. package/dist/commands/documents.js +36 -22
  18. package/dist/commands/dunning-configs.js +30 -18
  19. package/dist/commands/dunning-reminders.js +30 -18
  20. package/dist/commands/dunning-runs.js +30 -18
  21. package/dist/commands/employees.js +30 -18
  22. package/dist/commands/event-processor-mappings.js +30 -18
  23. package/dist/commands/files-internal.js +30 -18
  24. package/dist/commands/health.js +30 -18
  25. package/dist/commands/inbox.js +34 -20
  26. package/dist/commands/integrations.js +30 -18
  27. package/dist/commands/item-categories.js +30 -18
  28. package/dist/commands/items.js +30 -18
  29. package/dist/commands/journal-lines.js +30 -18
  30. package/dist/commands/journals.js +30 -18
  31. package/dist/commands/ledgers.js +30 -18
  32. package/dist/commands/office-locations.js +30 -18
  33. package/dist/commands/payment-method-ledger-mappings.js +30 -18
  34. package/dist/commands/payment-methods.js +30 -18
  35. package/dist/commands/payment-runs.js +30 -18
  36. package/dist/commands/payment-terms.js +30 -18
  37. package/dist/commands/price-lists.js +30 -18
  38. package/dist/commands/processor-mappings.js +30 -18
  39. package/dist/commands/processors.js +31 -19
  40. package/dist/commands/reconciliation.js +30 -18
  41. package/dist/commands/reports.js +30 -18
  42. package/dist/commands/salary-types.js +30 -18
  43. package/dist/commands/sales-invoices.js +32 -19
  44. package/dist/commands/sales-orders.js +33 -19
  45. package/dist/commands/switch.d.ts +1 -0
  46. package/dist/commands/switch.js +58 -3
  47. package/dist/commands/tags.js +30 -18
  48. package/dist/commands/tax-codes.js +30 -18
  49. package/dist/commands/tax-matrix.js +30 -18
  50. package/dist/commands/tenants.js +30 -18
  51. package/dist/commands/text-templates.js +30 -18
  52. package/dist/commands/tools.js +30 -18
  53. package/dist/commands/vendor-invoices.js +33 -19
  54. package/dist/commands/webhooks.js +30 -18
  55. package/dist/commands/workflows.js +30 -18
  56. package/dist/index 2.js +1 -0
  57. package/dist/index.d 2.ts +1 -0
  58. package/dist/lib/auth.d.ts +16 -1
  59. package/dist/lib/auth.js +167 -50
  60. package/dist/lib/config.d.ts +7 -0
  61. package/dist/lib/config.js +6 -0
  62. package/oclif.manifest.json +65 -385
  63. package/package.json +2 -2
  64. package/dist/commands/account-statement-runs.d.ts +0 -40
  65. package/dist/commands/account-statement-runs.js +0 -1004
  66. package/dist/commands/bank-statements.d.ts +0 -40
  67. package/dist/commands/bank-statements.js +0 -998
@@ -6,7 +6,7 @@ const HAS_IMPORT = true;
6
6
  const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
- const SUBCOMMANDS = [...["initiate", "providers-supported", "providers-consent-status", "delete-providers-consent", "list", "create", "get", "update", "delete", "log"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["initiate", "providers-supported", "providers-consent-status", "delete-providers-consent", "list", "create", "get", "update", "delete", "log", "list-account-statement-runs", "trigger-account-statement-runs", "get-account-statement-runs", "account-statement-runs-files", "trigger-account-statement-runs-reimport", "list-statements", "statements", "download-statements-xml"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
11
  'initiate': { method: 'POST', path: '/v1/bank-integrations/initiate', summary: 'Initiate the OAuth/auth flow for a bank integration', pathParams: [], hasBody: true, isMultipart: false },
12
12
  'providers-supported': { method: 'GET', path: '/v1/bank-integrations/providers/supported', summary: 'List supported bLink providers', pathParams: [], hasBody: false, isMultipart: false },
@@ -18,6 +18,14 @@ const ENDPOINTS = {
18
18
  'update': { method: 'PATCH', path: '/v1/bank-integrations/{id}', summary: 'Update the display name of a BankIntegration', pathParams: ['id'], hasBody: true, isMultipart: false },
19
19
  'delete': { method: 'DELETE', path: '/v1/bank-integrations/{id}', summary: 'Delete a BankIntegration', pathParams: ['id'], hasBody: false, isMultipart: false },
20
20
  'log': { method: 'GET', path: '/v1/bank-integrations/{id}/log', summary: 'Get activity log for a bank integration', pathParams: ['id'], hasBody: false, isMultipart: false },
21
+ 'list-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'List bank statement import runs', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false },
22
+ 'trigger-account-statement-runs': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs', summary: 'Trigger a bank statement import', pathParams: ['bankIntegrationId'], hasBody: true, isMultipart: false },
23
+ 'get-account-statement-runs': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}', summary: 'Get import run details', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false },
24
+ 'account-statement-runs-files': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/files', summary: 'Get files for an import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: false, isMultipart: false },
25
+ 'trigger-account-statement-runs-reimport': { method: 'POST', path: '/v1/bank-integrations/{bankIntegrationId}/account-statement-runs/{importRunId}/reimport', summary: 'Trigger reimport of an existing account statement import run', pathParams: ['bankIntegrationId', 'importRunId'], hasBody: true, isMultipart: false },
26
+ 'list-statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements', summary: 'List CAMT.053 statements for a bank integration', pathParams: ['bankIntegrationId'], hasBody: false, isMultipart: false },
27
+ 'statements': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}', summary: 'Get CAMT.053 statement detail', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false },
28
+ 'download-statements-xml': { method: 'GET', path: '/v1/bank-integrations/{bankIntegrationId}/statements/{statementId}/xml', summary: 'Get raw CAMT.053 XML for a statement', pathParams: ['bankIntegrationId', 'statementId'], hasBody: false, isMultipart: false },
21
29
  };
22
30
  export default class BankIntegrations extends Command {
23
31
  static description = 'Manage bank integrations';
@@ -41,6 +49,8 @@ export default class BankIntegrations extends Command {
41
49
  data: Flags.string({ char: 'd', description: 'JSON data for request body' }),
42
50
  file: Flags.string({ char: 'f', description: 'Read request body from file' }),
43
51
  set: Flags.string({ char: 's', description: 'Set individual field (e.g. --set firstName=John)', multiple: true }),
52
+ 'import-run-id': Flags.string({ description: 'Path param: importRunId' }),
53
+ 'statement-id': Flags.string({ description: 'Path param: statementId' }),
44
54
  page: Flags.string({ description: 'Page number' }),
45
55
  limit: Flags.string({ description: 'Items per page' }),
46
56
  include: Flags.string({ description: 'Relations to include' }),
@@ -824,32 +834,44 @@ export default class BankIntegrations extends Command {
824
834
  filterFields(data, fields) {
825
835
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
826
836
  const pick = (obj, keys) => {
827
- const result = {};
837
+ // Group keys by their first segment so sibling sub-paths
838
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
839
+ // and don't clobber each other on merge.
840
+ const directKeys = new Set();
841
+ const nestedKeys = new Map();
828
842
  for (const key of keys) {
829
843
  if (key.split('.').some(isUnsafeKey))
830
844
  continue;
831
845
  if (key.includes('.')) {
832
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
833
846
  const [first, ...rest] = key.split('.');
834
- const val = obj[first];
835
- if (val && typeof val === 'object') {
836
- const restKey = rest.join('.');
837
- if (Array.isArray(val)) {
838
- // Map over array elements (e.g., allocations[].salesInvoiceId)
839
- const existing = Array.isArray(result[first]) ? result[first] : [];
840
- result[first] = val.map((item, i) => ({
841
- ...(existing[i] || {}),
842
- ...pick(item, [restKey]),
843
- }));
844
- }
845
- else {
846
- const nested = pick(val, [restKey]);
847
- result[first] = { ...(result[first] || {}), ...nested };
848
- }
847
+ if (isUnsafeKey(first))
848
+ continue;
849
+ const list = nestedKeys.get(first);
850
+ if (list) {
851
+ list.push(rest.join('.'));
849
852
  }
853
+ else {
854
+ nestedKeys.set(first, [rest.join('.')]);
855
+ }
856
+ }
857
+ else {
858
+ directKeys.add(key);
850
859
  }
851
- else if (key in obj) {
860
+ }
861
+ const result = {};
862
+ for (const key of directKeys) {
863
+ if (key in obj)
852
864
  result[key] = obj[key];
865
+ }
866
+ for (const [first, restKeys] of nestedKeys) {
867
+ const val = obj[first];
868
+ if (!val || typeof val !== 'object')
869
+ continue;
870
+ if (Array.isArray(val)) {
871
+ result[first] = val.map(item => pick(item, restKeys));
872
+ }
873
+ else {
874
+ result[first] = pick(val, restKeys);
853
875
  }
854
876
  }
855
877
  return result;
@@ -819,32 +819,44 @@ export default class BusinessPartnersContacts extends Command {
819
819
  filterFields(data, fields) {
820
820
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
821
821
  const pick = (obj, keys) => {
822
- const result = {};
822
+ // Group keys by their first segment so sibling sub-paths
823
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
824
+ // and don't clobber each other on merge.
825
+ const directKeys = new Set();
826
+ const nestedKeys = new Map();
823
827
  for (const key of keys) {
824
828
  if (key.split('.').some(isUnsafeKey))
825
829
  continue;
826
830
  if (key.includes('.')) {
827
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
828
831
  const [first, ...rest] = key.split('.');
829
- const val = obj[first];
830
- if (val && typeof val === 'object') {
831
- const restKey = rest.join('.');
832
- if (Array.isArray(val)) {
833
- // Map over array elements (e.g., allocations[].salesInvoiceId)
834
- const existing = Array.isArray(result[first]) ? result[first] : [];
835
- result[first] = val.map((item, i) => ({
836
- ...(existing[i] || {}),
837
- ...pick(item, [restKey]),
838
- }));
839
- }
840
- else {
841
- const nested = pick(val, [restKey]);
842
- result[first] = { ...(result[first] || {}), ...nested };
843
- }
832
+ if (isUnsafeKey(first))
833
+ continue;
834
+ const list = nestedKeys.get(first);
835
+ if (list) {
836
+ list.push(rest.join('.'));
844
837
  }
838
+ else {
839
+ nestedKeys.set(first, [rest.join('.')]);
840
+ }
841
+ }
842
+ else {
843
+ directKeys.add(key);
845
844
  }
846
- else if (key in obj) {
845
+ }
846
+ const result = {};
847
+ for (const key of directKeys) {
848
+ if (key in obj)
847
849
  result[key] = obj[key];
850
+ }
851
+ for (const [first, restKeys] of nestedKeys) {
852
+ const val = obj[first];
853
+ if (!val || typeof val !== 'object')
854
+ continue;
855
+ if (Array.isArray(val)) {
856
+ result[first] = val.map(item => pick(item, restKeys));
857
+ }
858
+ else {
859
+ result[first] = pick(val, restKeys);
848
860
  }
849
861
  }
850
862
  return result;
@@ -825,32 +825,44 @@ export default class BusinessPartners extends Command {
825
825
  filterFields(data, fields) {
826
826
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
827
827
  const pick = (obj, keys) => {
828
- const result = {};
828
+ // Group keys by their first segment so sibling sub-paths
829
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
830
+ // and don't clobber each other on merge.
831
+ const directKeys = new Set();
832
+ const nestedKeys = new Map();
829
833
  for (const key of keys) {
830
834
  if (key.split('.').some(isUnsafeKey))
831
835
  continue;
832
836
  if (key.includes('.')) {
833
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
834
837
  const [first, ...rest] = key.split('.');
835
- const val = obj[first];
836
- if (val && typeof val === 'object') {
837
- const restKey = rest.join('.');
838
- if (Array.isArray(val)) {
839
- // Map over array elements (e.g., allocations[].salesInvoiceId)
840
- const existing = Array.isArray(result[first]) ? result[first] : [];
841
- result[first] = val.map((item, i) => ({
842
- ...(existing[i] || {}),
843
- ...pick(item, [restKey]),
844
- }));
845
- }
846
- else {
847
- const nested = pick(val, [restKey]);
848
- result[first] = { ...(result[first] || {}), ...nested };
849
- }
838
+ if (isUnsafeKey(first))
839
+ continue;
840
+ const list = nestedKeys.get(first);
841
+ if (list) {
842
+ list.push(rest.join('.'));
850
843
  }
844
+ else {
845
+ nestedKeys.set(first, [rest.join('.')]);
846
+ }
847
+ }
848
+ else {
849
+ directKeys.add(key);
851
850
  }
852
- else if (key in obj) {
851
+ }
852
+ const result = {};
853
+ for (const key of directKeys) {
854
+ if (key in obj)
853
855
  result[key] = obj[key];
856
+ }
857
+ for (const [first, restKeys] of nestedKeys) {
858
+ const val = obj[first];
859
+ if (!val || typeof val !== 'object')
860
+ continue;
861
+ if (Array.isArray(val)) {
862
+ result[first] = val.map(item => pick(item, restKeys));
863
+ }
864
+ else {
865
+ result[first] = pick(val, restKeys);
854
866
  }
855
867
  }
856
868
  return result;
@@ -831,32 +831,44 @@ export default class CreditCardAccounts extends Command {
831
831
  filterFields(data, fields) {
832
832
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
833
833
  const pick = (obj, keys) => {
834
- const result = {};
834
+ // Group keys by their first segment so sibling sub-paths
835
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
836
+ // and don't clobber each other on merge.
837
+ const directKeys = new Set();
838
+ const nestedKeys = new Map();
835
839
  for (const key of keys) {
836
840
  if (key.split('.').some(isUnsafeKey))
837
841
  continue;
838
842
  if (key.includes('.')) {
839
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
840
843
  const [first, ...rest] = key.split('.');
841
- const val = obj[first];
842
- if (val && typeof val === 'object') {
843
- const restKey = rest.join('.');
844
- if (Array.isArray(val)) {
845
- // Map over array elements (e.g., allocations[].salesInvoiceId)
846
- const existing = Array.isArray(result[first]) ? result[first] : [];
847
- result[first] = val.map((item, i) => ({
848
- ...(existing[i] || {}),
849
- ...pick(item, [restKey]),
850
- }));
851
- }
852
- else {
853
- const nested = pick(val, [restKey]);
854
- result[first] = { ...(result[first] || {}), ...nested };
855
- }
844
+ if (isUnsafeKey(first))
845
+ continue;
846
+ const list = nestedKeys.get(first);
847
+ if (list) {
848
+ list.push(rest.join('.'));
856
849
  }
850
+ else {
851
+ nestedKeys.set(first, [rest.join('.')]);
852
+ }
853
+ }
854
+ else {
855
+ directKeys.add(key);
857
856
  }
858
- else if (key in obj) {
857
+ }
858
+ const result = {};
859
+ for (const key of directKeys) {
860
+ if (key in obj)
859
861
  result[key] = obj[key];
862
+ }
863
+ for (const [first, restKeys] of nestedKeys) {
864
+ const val = obj[first];
865
+ if (!val || typeof val !== 'object')
866
+ continue;
867
+ if (Array.isArray(val)) {
868
+ result[first] = val.map(item => pick(item, restKeys));
869
+ }
870
+ else {
871
+ result[first] = pick(val, restKeys);
860
872
  }
861
873
  }
862
874
  return result;
@@ -3,14 +3,14 @@ import { apiRequest, ApiError } from '../lib/api-client.js';
3
3
  import { getCurrentContext, getContext, getBaseUrls } from '../lib/config.js';
4
4
  // Add 'import' action if both create and update exist
5
5
  const HAS_IMPORT = true;
6
- const HAS_EXPORT = false;
6
+ const HAS_EXPORT = true;
7
7
  const HAS_CAMT053 = false;
8
8
  const NESTED_IMPORTS = [];
9
- const SUBCOMMANDS = [...["get", "create", "get-all", "update", "delete", "reclassify"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
9
+ const SUBCOMMANDS = [...["list", "create", "get", "update", "delete", "reclassify"], ...(HAS_IMPORT ? ['import'] : []), ...(HAS_EXPORT ? ['export'] : []), ...NESTED_IMPORTS.map(n => `import-${n}`)];
10
10
  const ENDPOINTS = {
11
- 'get': { method: 'GET', path: '/v1/documents', summary: 'List documents (paginated)', pathParams: [], hasBody: false, isMultipart: false },
11
+ 'list': { method: 'GET', path: '/v1/documents', summary: 'List documents (paginated)', pathParams: [], hasBody: false, isMultipart: false },
12
12
  'create': { method: 'POST', path: '/v1/documents', summary: 'Create a new document (letterbox)', pathParams: [], hasBody: true, isMultipart: false },
13
- 'get-all': { method: 'GET', path: '/v1/documents/{id}', summary: 'Get document detail with files, audit log, and notes placeholder', pathParams: ['id'], hasBody: false, isMultipart: false },
13
+ 'get': { method: 'GET', path: '/v1/documents/{id}', summary: 'Get document detail with files, audit log, and notes placeholder', pathParams: ['id'], hasBody: false, isMultipart: false },
14
14
  'update': { method: 'PATCH', path: '/v1/documents/{id}', summary: 'Patch an existing document', pathParams: ['id'], hasBody: true, isMultipart: false },
15
15
  'delete': { method: 'DELETE', path: '/v1/documents/{id}', summary: 'Soft-delete (discard) a document', pathParams: ['id'], hasBody: true, isMultipart: false },
16
16
  'reclassify': { method: 'POST', path: '/v1/documents/{id}/reclassify', summary: 'Reclassify a document to a new type', pathParams: ['id'], hasBody: true, isMultipart: false },
@@ -18,10 +18,12 @@ const ENDPOINTS = {
18
18
  export default class Documents extends Command {
19
19
  static description = 'Manage documents';
20
20
  static examples = [
21
+ '<%= config.bin %> documents list',
21
22
  '<%= config.bin %> documents get <id>',
22
23
  '<%= config.bin %> documents create --data \'{...}\'',
23
24
  '<%= config.bin %> documents update <id> --set field=value',
24
25
  '<%= config.bin %> documents import --file data.json',
26
+ '<%= config.bin %> documents export --csv > documents.csv',
25
27
  ];
26
28
  static args = {
27
29
  action: Args.string({ description: 'Action: ' + SUBCOMMANDS.join(', '), required: true }),
@@ -818,32 +820,44 @@ export default class Documents extends Command {
818
820
  filterFields(data, fields) {
819
821
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
820
822
  const pick = (obj, keys) => {
821
- const result = {};
823
+ // Group keys by their first segment so sibling sub-paths
824
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
825
+ // and don't clobber each other on merge.
826
+ const directKeys = new Set();
827
+ const nestedKeys = new Map();
822
828
  for (const key of keys) {
823
829
  if (key.split('.').some(isUnsafeKey))
824
830
  continue;
825
831
  if (key.includes('.')) {
826
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
827
832
  const [first, ...rest] = key.split('.');
828
- const val = obj[first];
829
- if (val && typeof val === 'object') {
830
- const restKey = rest.join('.');
831
- if (Array.isArray(val)) {
832
- // Map over array elements (e.g., allocations[].salesInvoiceId)
833
- const existing = Array.isArray(result[first]) ? result[first] : [];
834
- result[first] = val.map((item, i) => ({
835
- ...(existing[i] || {}),
836
- ...pick(item, [restKey]),
837
- }));
838
- }
839
- else {
840
- const nested = pick(val, [restKey]);
841
- result[first] = { ...(result[first] || {}), ...nested };
842
- }
833
+ if (isUnsafeKey(first))
834
+ continue;
835
+ const list = nestedKeys.get(first);
836
+ if (list) {
837
+ list.push(rest.join('.'));
843
838
  }
839
+ else {
840
+ nestedKeys.set(first, [rest.join('.')]);
841
+ }
842
+ }
843
+ else {
844
+ directKeys.add(key);
844
845
  }
845
- else if (key in obj) {
846
+ }
847
+ const result = {};
848
+ for (const key of directKeys) {
849
+ if (key in obj)
846
850
  result[key] = obj[key];
851
+ }
852
+ for (const [first, restKeys] of nestedKeys) {
853
+ const val = obj[first];
854
+ if (!val || typeof val !== 'object')
855
+ continue;
856
+ if (Array.isArray(val)) {
857
+ result[first] = val.map(item => pick(item, restKeys));
858
+ }
859
+ else {
860
+ result[first] = pick(val, restKeys);
847
861
  }
848
862
  }
849
863
  return result;
@@ -819,32 +819,44 @@ export default class DunningConfigs extends Command {
819
819
  filterFields(data, fields) {
820
820
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
821
821
  const pick = (obj, keys) => {
822
- const result = {};
822
+ // Group keys by their first segment so sibling sub-paths
823
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
824
+ // and don't clobber each other on merge.
825
+ const directKeys = new Set();
826
+ const nestedKeys = new Map();
823
827
  for (const key of keys) {
824
828
  if (key.split('.').some(isUnsafeKey))
825
829
  continue;
826
830
  if (key.includes('.')) {
827
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
828
831
  const [first, ...rest] = key.split('.');
829
- const val = obj[first];
830
- if (val && typeof val === 'object') {
831
- const restKey = rest.join('.');
832
- if (Array.isArray(val)) {
833
- // Map over array elements (e.g., allocations[].salesInvoiceId)
834
- const existing = Array.isArray(result[first]) ? result[first] : [];
835
- result[first] = val.map((item, i) => ({
836
- ...(existing[i] || {}),
837
- ...pick(item, [restKey]),
838
- }));
839
- }
840
- else {
841
- const nested = pick(val, [restKey]);
842
- result[first] = { ...(result[first] || {}), ...nested };
843
- }
832
+ if (isUnsafeKey(first))
833
+ continue;
834
+ const list = nestedKeys.get(first);
835
+ if (list) {
836
+ list.push(rest.join('.'));
844
837
  }
838
+ else {
839
+ nestedKeys.set(first, [rest.join('.')]);
840
+ }
841
+ }
842
+ else {
843
+ directKeys.add(key);
845
844
  }
846
- else if (key in obj) {
845
+ }
846
+ const result = {};
847
+ for (const key of directKeys) {
848
+ if (key in obj)
847
849
  result[key] = obj[key];
850
+ }
851
+ for (const [first, restKeys] of nestedKeys) {
852
+ const val = obj[first];
853
+ if (!val || typeof val !== 'object')
854
+ continue;
855
+ if (Array.isArray(val)) {
856
+ result[first] = val.map(item => pick(item, restKeys));
857
+ }
858
+ else {
859
+ result[first] = pick(val, restKeys);
848
860
  }
849
861
  }
850
862
  return result;
@@ -820,32 +820,44 @@ export default class DunningReminders extends Command {
820
820
  filterFields(data, fields) {
821
821
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
822
822
  const pick = (obj, keys) => {
823
- const result = {};
823
+ // Group keys by their first segment so sibling sub-paths
824
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
825
+ // and don't clobber each other on merge.
826
+ const directKeys = new Set();
827
+ const nestedKeys = new Map();
824
828
  for (const key of keys) {
825
829
  if (key.split('.').some(isUnsafeKey))
826
830
  continue;
827
831
  if (key.includes('.')) {
828
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
829
832
  const [first, ...rest] = key.split('.');
830
- const val = obj[first];
831
- if (val && typeof val === 'object') {
832
- const restKey = rest.join('.');
833
- if (Array.isArray(val)) {
834
- // Map over array elements (e.g., allocations[].salesInvoiceId)
835
- const existing = Array.isArray(result[first]) ? result[first] : [];
836
- result[first] = val.map((item, i) => ({
837
- ...(existing[i] || {}),
838
- ...pick(item, [restKey]),
839
- }));
840
- }
841
- else {
842
- const nested = pick(val, [restKey]);
843
- result[first] = { ...(result[first] || {}), ...nested };
844
- }
833
+ if (isUnsafeKey(first))
834
+ continue;
835
+ const list = nestedKeys.get(first);
836
+ if (list) {
837
+ list.push(rest.join('.'));
845
838
  }
839
+ else {
840
+ nestedKeys.set(first, [rest.join('.')]);
841
+ }
842
+ }
843
+ else {
844
+ directKeys.add(key);
846
845
  }
847
- else if (key in obj) {
846
+ }
847
+ const result = {};
848
+ for (const key of directKeys) {
849
+ if (key in obj)
848
850
  result[key] = obj[key];
851
+ }
852
+ for (const [first, restKeys] of nestedKeys) {
853
+ const val = obj[first];
854
+ if (!val || typeof val !== 'object')
855
+ continue;
856
+ if (Array.isArray(val)) {
857
+ result[first] = val.map(item => pick(item, restKeys));
858
+ }
859
+ else {
860
+ result[first] = pick(val, restKeys);
849
861
  }
850
862
  }
851
863
  return result;
@@ -808,32 +808,44 @@ export default class DunningRuns extends Command {
808
808
  filterFields(data, fields) {
809
809
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
810
810
  const pick = (obj, keys) => {
811
- const result = {};
811
+ // Group keys by their first segment so sibling sub-paths
812
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
813
+ // and don't clobber each other on merge.
814
+ const directKeys = new Set();
815
+ const nestedKeys = new Map();
812
816
  for (const key of keys) {
813
817
  if (key.split('.').some(isUnsafeKey))
814
818
  continue;
815
819
  if (key.includes('.')) {
816
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
817
820
  const [first, ...rest] = key.split('.');
818
- const val = obj[first];
819
- if (val && typeof val === 'object') {
820
- const restKey = rest.join('.');
821
- if (Array.isArray(val)) {
822
- // Map over array elements (e.g., allocations[].salesInvoiceId)
823
- const existing = Array.isArray(result[first]) ? result[first] : [];
824
- result[first] = val.map((item, i) => ({
825
- ...(existing[i] || {}),
826
- ...pick(item, [restKey]),
827
- }));
828
- }
829
- else {
830
- const nested = pick(val, [restKey]);
831
- result[first] = { ...(result[first] || {}), ...nested };
832
- }
821
+ if (isUnsafeKey(first))
822
+ continue;
823
+ const list = nestedKeys.get(first);
824
+ if (list) {
825
+ list.push(rest.join('.'));
833
826
  }
827
+ else {
828
+ nestedKeys.set(first, [rest.join('.')]);
829
+ }
830
+ }
831
+ else {
832
+ directKeys.add(key);
834
833
  }
835
- else if (key in obj) {
834
+ }
835
+ const result = {};
836
+ for (const key of directKeys) {
837
+ if (key in obj)
836
838
  result[key] = obj[key];
839
+ }
840
+ for (const [first, restKeys] of nestedKeys) {
841
+ const val = obj[first];
842
+ if (!val || typeof val !== 'object')
843
+ continue;
844
+ if (Array.isArray(val)) {
845
+ result[first] = val.map(item => pick(item, restKeys));
846
+ }
847
+ else {
848
+ result[first] = pick(val, restKeys);
837
849
  }
838
850
  }
839
851
  return result;
@@ -850,32 +850,44 @@ export default class Employees extends Command {
850
850
  filterFields(data, fields) {
851
851
  const isUnsafeKey = (k) => k === '__proto__' || k === 'constructor' || k === 'prototype';
852
852
  const pick = (obj, keys) => {
853
- const result = {};
853
+ // Group keys by their first segment so sibling sub-paths
854
+ // (e.g. 'items.amount' + 'items._type') resolve in one recursive pass
855
+ // and don't clobber each other on merge.
856
+ const directKeys = new Set();
857
+ const nestedKeys = new Map();
854
858
  for (const key of keys) {
855
859
  if (key.split('.').some(isUnsafeKey))
856
860
  continue;
857
861
  if (key.includes('.')) {
858
- // Handle nested fields like 'customer.name' or 'allocations.salesInvoiceId'
859
862
  const [first, ...rest] = key.split('.');
860
- const val = obj[first];
861
- if (val && typeof val === 'object') {
862
- const restKey = rest.join('.');
863
- if (Array.isArray(val)) {
864
- // Map over array elements (e.g., allocations[].salesInvoiceId)
865
- const existing = Array.isArray(result[first]) ? result[first] : [];
866
- result[first] = val.map((item, i) => ({
867
- ...(existing[i] || {}),
868
- ...pick(item, [restKey]),
869
- }));
870
- }
871
- else {
872
- const nested = pick(val, [restKey]);
873
- result[first] = { ...(result[first] || {}), ...nested };
874
- }
863
+ if (isUnsafeKey(first))
864
+ continue;
865
+ const list = nestedKeys.get(first);
866
+ if (list) {
867
+ list.push(rest.join('.'));
875
868
  }
869
+ else {
870
+ nestedKeys.set(first, [rest.join('.')]);
871
+ }
872
+ }
873
+ else {
874
+ directKeys.add(key);
876
875
  }
877
- else if (key in obj) {
876
+ }
877
+ const result = {};
878
+ for (const key of directKeys) {
879
+ if (key in obj)
878
880
  result[key] = obj[key];
881
+ }
882
+ for (const [first, restKeys] of nestedKeys) {
883
+ const val = obj[first];
884
+ if (!val || typeof val !== 'object')
885
+ continue;
886
+ if (Array.isArray(val)) {
887
+ result[first] = val.map(item => pick(item, restKeys));
888
+ }
889
+ else {
890
+ result[first] = pick(val, restKeys);
879
891
  }
880
892
  }
881
893
  return result;