@zeniai/client-epic-state 5.0.31-betaAR9 → 5.0.31-betaML1

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 (79) hide show
  1. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
  2. package/lib/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  3. package/lib/entity/account/accountSelector.d.ts +6 -33
  4. package/lib/entity/account/accountSelector.js +8 -37
  5. package/lib/entity/account/accountState.d.ts +1 -6
  6. package/lib/entity/account/accountState.js +4 -11
  7. package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
  8. package/lib/entity/class/classReducer.d.ts +4 -4
  9. package/lib/entity/class/classSelector.d.ts +0 -5
  10. package/lib/entity/class/classSelector.js +0 -8
  11. package/lib/entity/class/classState.d.ts +1 -1
  12. package/lib/entity/forecast/forecastState.d.ts +1 -1
  13. package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
  14. package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
  15. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
  16. package/lib/entity/sectionProjectView/sectionProjectView.d.ts +1 -1
  17. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +2 -2
  18. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  19. package/lib/entity/snackbar/snackbarTypes.js +2 -0
  20. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +6 -0
  21. package/lib/entity/transaction/payloadTypes/transactionPayload.js +10 -0
  22. package/lib/entity/transaction/stateTypes/transaction.d.ts +6 -0
  23. package/lib/epic.d.ts +3 -1
  24. package/lib/epic.js +3 -1
  25. package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  26. package/lib/esm/entity/account/accountSelector.js +7 -35
  27. package/lib/esm/entity/account/accountState.js +1 -7
  28. package/lib/esm/entity/class/classSelector.js +0 -7
  29. package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
  30. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +10 -0
  31. package/lib/esm/epic.js +3 -1
  32. package/lib/esm/index.js +14 -15
  33. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.js +81 -0
  34. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
  35. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +5 -1
  36. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.js +25 -0
  37. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +66 -11
  38. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -57
  39. package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +15 -185
  40. package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  41. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +12 -1
  42. package/lib/index.d.ts +20 -20
  43. package/lib/index.js +51 -49
  44. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  45. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  46. package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
  47. package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
  48. package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
  49. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
  50. package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
  51. package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
  52. package/lib/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.d.ts +9 -0
  53. package/lib/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.js +85 -0
  54. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
  55. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.d.ts +2 -2
  56. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -0
  57. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.d.ts +8 -0
  58. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.js +29 -0
  59. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  60. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +16 -6
  61. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +67 -12
  62. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +3 -1
  63. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +3 -4
  64. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -59
  65. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +13 -3
  66. package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
  67. package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
  68. package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
  69. package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
  70. package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +4 -45
  71. package/lib/view/spendManagement/spendManagementFilterHelpers.js +16 -186
  72. package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
  73. package/lib/view/topEx/topExSelector.d.ts +1 -1
  74. package/lib/view/transactionDetail/epics/transactionDetailEpic.d.ts +2 -1
  75. package/lib/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  76. package/lib/view/transactionDetail/transactionDetailPayload.d.ts +1 -1
  77. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +4 -1
  78. package/lib/view/transactionDetail/transactionDetailSelector.js +12 -1
  79. package/package.json +1 -1
@@ -1,35 +1,20 @@
1
1
  import omit from 'lodash/omit';
2
2
  import { reduceAllFetchState, reduceAnyFetchState, } from '../../../commonStateTypes/reduceFetchState';
3
3
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
4
+ import { getAccountBase, getAccountBaseForTransferAccounts, } from '../../../entity/account/accountSelector';
4
5
  import { getIsAccountingClassesEnabled, getCurrentTenant, } from '../../../entity/tenant/tenantSelector';
5
6
  import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
6
7
  import { getSupportedTransactionsByIds } from '../../../entity/transaction/transactionSelector';
7
- import { applyAdvancedFiltersOnList, } from '../../spendManagement/spendManagementFilterHelpers';
8
8
  import { getAccountList, getNestedAccountListHierarchy, getUncategorizedAccounts, } from '../../accountList/accountListSelector';
9
9
  import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
10
10
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
11
- export const toTransactionView = (transaction, transactionLocalData) => {
12
- return {
13
- id: transaction.id,
14
- date: transaction.date,
15
- amount: transaction.amount,
16
- vendorName: transaction.vendorName,
17
- customerName: transaction.customerName,
18
- vendorId: transaction.vendorId,
19
- customerId: transaction.customerId,
20
- description: transaction.description,
21
- memo: transaction.memo,
22
- type: transaction.type,
23
- typeName: transaction.typeName,
24
- createTime: transaction.createTime,
25
- transaction: transaction,
26
- transactionLocalData,
27
- };
28
- };
11
+ export function getLastTransferEntryReplacement(state) {
12
+ return state.expenseAutomationTransactionsViewState.lastTransferEntryReplacement;
13
+ }
29
14
  export function getExpenseAutomationTransactionView(state) {
30
15
  const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
31
16
  const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
32
- const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, filters, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
17
+ const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
33
18
  const uncategorizedIncomeExpense = getUncategorizedAccounts(accountState, accountListState, 'accountList');
34
19
  const accountList = getAccountList(accountState, accountListState, 'accountList');
35
20
  const classList = getClassList(classState, classListState);
@@ -46,42 +31,10 @@ export function getExpenseAutomationTransactionView(state) {
46
31
  ? transactionIdsBySelectedPeriod[monthYearPeriodId]
47
32
  : null;
48
33
  const transactionIds = transactionIdsForSelectedPeriod ?? [];
49
- const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
50
- const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
51
- const transactionLocalDataMap = new Map();
52
- transactionIds.forEach((transactionId) => {
53
- const transactionData = transactionReviewLocalDataById[transactionId];
54
- if (transactionData != null) {
55
- transactionLocalDataMap.set(transactionId, {
56
- transactionId,
57
- transactionReviewLocalData: transactionData.transactionReviewLocalData,
58
- });
59
- }
60
- });
61
- // Step 2: Convert to TransactionView and apply advanced filters
62
- const transactionViews = transactionsWithCOT.map((transaction) => {
63
- const localData = transactionLocalDataMap.get(transaction.id);
64
- return toTransactionView(transaction, localData);
65
- });
66
- // Apply advanced filters if they exist
67
- const filteredTransactionViews = applyAdvancedFiltersOnList('transaction_categorization', transactionViews, filters);
68
- // Convert back to TransactionWithCOT for return
69
- const filteredTransactionsWithCOT = filteredTransactionViews.map((view) => view.transaction);
70
- // Get transactionLocalData for filtered transactions
71
- // Also include transactionLocalData for transactions that don't exist in transactionState
72
- // but have local data (to match original behavior)
73
- const filteredTransactionIds = new Set(filteredTransactionViews.map((view) => view.id));
74
- const filteredTransactionLocalData = transactionIds
34
+ const transactionLocalData = transactionIds
75
35
  .map((transactionId) => {
76
36
  const transactionData = transactionReviewLocalDataById[transactionId];
77
- if (transactionData == null) {
78
- return null;
79
- }
80
- // Include if transaction is in filtered results, or if transaction doesn't exist in state
81
- // (to maintain backward compatibility with tests)
82
- const transactionExists = transactions.some((t) => t.id === transactionId);
83
- if (filteredTransactionIds.has(transactionId) ||
84
- !transactionExists) {
37
+ if (transactionData != null) {
85
38
  return {
86
39
  transactionId,
87
40
  transactionReviewLocalData: transactionData.transactionReviewLocalData,
@@ -89,7 +42,9 @@ export function getExpenseAutomationTransactionView(state) {
89
42
  }
90
43
  return null;
91
44
  })
92
- .filter((data) => data != null);
45
+ .filter((transaction) => transaction != null);
46
+ const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
47
+ const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
93
48
  const monthEndFetchState = monthYearPeriodId != null
94
49
  ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
95
50
  : { fetchState: 'Not-Started', error: undefined };
@@ -132,11 +87,24 @@ export function getExpenseAutomationTransactionView(state) {
132
87
  : [];
133
88
  const transactionCompletionStatus = allSteps.find((step) => step.step === 'transaction_categorization')?.completionStatus;
134
89
  const completionStatus = transactionCompletionStatus ?? 'incomplete';
90
+ const transferAccountsFromApi = expenseAutomationTransactionsViewState.transferAccounts.accountIds
91
+ .map((id) => getAccountBaseForTransferAccounts(accountState, id))
92
+ .filter((account) => account != null);
93
+ /**
94
+ * Credit transfer picker uses transfer-account ids from a dedicated fetch. If that list
95
+ * resolves to nothing while the COA list is loaded, fall back to the full COA list so the
96
+ * credit dropdown is not empty.
97
+ */
98
+ const transferAccountsList = transferAccountsFromApi.length > 0
99
+ ? transferAccountsFromApi
100
+ : accountList.accounts
101
+ .map((a) => getAccountBase(accountState, a.accountId, 'account_list'))
102
+ .filter((account) => account != null);
135
103
  return {
136
104
  version: 0,
137
105
  fetchState: fetchStatus.fetchState,
138
106
  error: fetchStatus.error,
139
- transactions: filteredTransactionsWithCOT,
107
+ transactions: transactionsWithCOT,
140
108
  selectedCheckBoxTransactionIds,
141
109
  transactionIdsWithUnsavedData,
142
110
  uncategorizedAccounts: uncategorizedIncomeExpense,
@@ -145,16 +113,18 @@ export function getExpenseAutomationTransactionView(state) {
145
113
  classList: allClasses,
146
114
  accountsHierarchyList,
147
115
  classHierarchyList,
148
- transactionLocalData: filteredTransactionLocalData,
116
+ transactionLocalData,
149
117
  uiState,
150
118
  refreshStatus,
151
119
  saveStatus,
152
120
  markAsNotMiscategorizedStatus,
121
+ createTransferEntryStatus: expenseAutomationTransactionsViewState.createTransferEntryStatus,
153
122
  completionStatus,
154
123
  totalCountByTab,
155
124
  fetchStateByTransactionTabs: fetchStateByTab,
156
125
  uploadReceiptStatusById,
157
126
  selectedTransactionId,
158
127
  selectedTransactionLineId,
128
+ transferAccounts: transferAccountsList,
159
129
  };
160
130
  }
@@ -7,81 +7,28 @@ import { ALL_BILL_TABS, getBillListKey, } from './billPay/billList/billListState
7
7
  import { getActualPaymentDate } from './helpers';
8
8
  import { getApproversOrRejectors as getApproversOrRejectorsForReimbursement, } from './reimbursement/remiListView/remiListSelector';
9
9
  import { ALL_REMI_TABS, getRemiListKey, } from './reimbursement/remiListView/remiListState';
10
- export const TRANSACTION_FILTER_CATEGORIES = [
11
- { value: 'payment_account_name', type: 'dropdown' },
12
- { value: 'payment_account_type', type: 'dropdown' },
13
- { value: 'payee', type: 'searchAutocomplete' },
14
- { value: 'category', type: 'dropdown' },
15
- { value: 'class', type: 'dropdown' },
16
- { value: 'amount', type: 'numberRange' },
17
- ];
18
10
  //filters items against filter values representing a range. ex: date (from-to), amount(1k<-->5k)
19
- // For amount: supports new transaction_categorization operators (inBetween, lessThan, greaterThan) and
20
- // backward compatibility for old format values: ["1000<->5000"] with matchingOperator "equal".
21
- // Other entities (bill_pay, reimbursement, etc.) use only equal/not-equal and are unchanged.
22
11
  const filterItemOnRangeCategoryType = (valueForItem, currentFilter) => {
23
12
  let doesItemFallInValueRange = false;
24
13
  const filterField = currentFilter.field;
25
14
  if (filterField === 'amount') {
26
- const currentValue = Number(valueForItem);
27
- const op = currentFilter.matchingOperator;
28
- const values = currentFilter.values;
29
- if (op === 'inBetween') {
30
- // New format: values = [min, max] (expense automation transaction_categorization only)
31
- if (values.length >= 2) {
32
- const min = Number(values[0]);
33
- const max = Number(values[1]);
34
- doesItemFallInValueRange = currentValue >= min && currentValue <= max;
35
- }
36
- }
37
- else if (op === 'lessThan') {
38
- if (values.length >= 1) {
39
- const threshold = Number(values[0]);
40
- doesItemFallInValueRange = currentValue < threshold;
41
- }
42
- }
43
- else if (op === 'greaterThan') {
44
- if (values.length >= 1) {
45
- const threshold = Number(values[0]);
46
- doesItemFallInValueRange = currentValue > threshold;
47
- }
48
- }
49
- else if (op === 'equal' &&
50
- values.length === 1 &&
51
- String(values[0]).includes('<->')) {
52
- // Backward compatibility: old format ["1000<->5000"] with matchingOperator "equal"
53
- const parts = String(values[0]).split('<->');
54
- const lowerValue = Number(parts[0] ?? '');
55
- const higherValue = Number(parts[1] ?? '');
56
- doesItemFallInValueRange =
57
- currentValue >= lowerValue && currentValue <= higherValue;
58
- }
59
- else if (op === 'equal' && values.length === 1) {
60
- // New format: exact match on single value (expense automation)
61
- const val = Number(values[0]);
62
- doesItemFallInValueRange = currentValue === val;
63
- }
64
- else {
65
- // Existing logic for equal/not-equal (bill_pay, reimbursement, etc. or multiple range values)
66
- for (const filterValue of values) {
67
- const lowerValue = Number.parseInt(filterValue?.toString()?.split('<->')[0] ?? '', 10);
68
- const higherValue = Number.parseInt(filterValue?.toString()?.split('<->')[1] ?? '', 10);
69
- if (currentValue >= lowerValue && currentValue <= higherValue) {
70
- doesItemFallInValueRange = true;
71
- }
15
+ for (const filterValue of currentFilter.values) {
16
+ const currentValue = parseInt(valueForItem.toString());
17
+ const lowerValue = parseInt(filterValue?.toString()?.split('<->')[0] ?? '');
18
+ const higherValue = parseInt(filterValue?.toString()?.split('<->')[1] ?? '');
19
+ if (currentValue >= lowerValue && currentValue <= higherValue) {
20
+ doesItemFallInValueRange = true;
72
21
  }
73
22
  }
74
- return op === 'not-equal'
75
- ? !doesItemFallInValueRange
76
- : doesItemFallInValueRange;
77
23
  }
78
- // Date range and other range fields (unchanged for other entities)
79
- const currentValue = valueForItem;
80
- const lowerValue = currentFilter.values[0];
81
- const higherValue = currentFilter.values[1];
82
- if (currentValue.isSameOrAfter(lowerValue) &&
83
- currentValue.isSameOrBefore(higherValue)) {
84
- doesItemFallInValueRange = true;
24
+ else {
25
+ const currentValue = valueForItem;
26
+ const lowerValue = currentFilter.values[0];
27
+ const higherValue = currentFilter.values[1];
28
+ if (currentValue.isSameOrAfter(lowerValue) &&
29
+ currentValue.isSameOrBefore(higherValue)) {
30
+ doesItemFallInValueRange = true;
31
+ }
85
32
  }
86
33
  return currentFilter.matchingOperator === 'equal'
87
34
  ? doesItemFallInValueRange
@@ -166,11 +113,7 @@ export const applyAdvancedFiltersOnList = (entity, allItems, filters, filteredIt
166
113
  ? getCategoryValueForReimbursement(key, item)
167
114
  : entity === 'task_management'
168
115
  ? getCategoryValueForTaskList(key, item)
169
- : entity === 'transaction_categorization'
170
- ? getCategoryValueForTransaction(key, item)
171
- : entity === 'charge_card_payment_history'
172
- ? getCategoryValueForPaymentHistory(key, item)
173
- : undefined;
116
+ : getCategoryValueForPaymentHistory(key, item);
174
117
  if (categoryValue == null) {
175
118
  if (currentFilter.matchingOperator === 'not-equal') {
176
119
  return true;
@@ -291,119 +234,6 @@ const getCategoryValueForReimbursement = (key, reimbursement) => {
291
234
  return undefined;
292
235
  }
293
236
  };
294
- const getCategoryValueForTransaction = (key, transaction) => {
295
- switch (key) {
296
- case 'amount': {
297
- // Get from transactionLocalData line items (preferred) - sum all line item amounts
298
- const localDataForAmount = transaction.transactionLocalData?.transactionReviewLocalData;
299
- if (localDataForAmount?.lineItemById) {
300
- const lineItems = Object.values(localDataForAmount.lineItemById);
301
- if (lineItems.length > 0) {
302
- // Sum all line item amounts
303
- const totalAmount = lineItems.reduce((sum, lineItem) => sum + (lineItem.amount?.amount ?? 0), 0);
304
- return totalAmount;
305
- }
306
- }
307
- // Fallback to transaction-level amount or sum from transaction lines
308
- if (transaction.transaction.lines &&
309
- transaction.transaction.lines.length > 0) {
310
- const totalAmount = transaction.transaction.lines.reduce((sum, line) => sum + (line.amount?.amount ?? 0), 0);
311
- return totalAmount;
312
- }
313
- // Final fallback to transaction amount
314
- return transaction.amount.amount;
315
- }
316
- case 'payee': {
317
- // Priority: vendorName > customerName > from transactionLocalData
318
- if (transaction.vendorName) {
319
- return transaction.vendorName;
320
- }
321
- if (transaction.customerName) {
322
- return transaction.customerName;
323
- }
324
- // Check transactionLocalData for vendor/customer
325
- const localData = transaction.transactionLocalData?.transactionReviewLocalData;
326
- if (localData?.vendor?.name) {
327
- return localData.vendor.name;
328
- }
329
- if (localData?.customer?.name) {
330
- return localData.customer.name;
331
- }
332
- return undefined;
333
- }
334
- case 'payment_account_name': {
335
- // Match the value the row renders: TransactionCategorizationListRow reads
336
- // `currentTransaction?.account?.accountName` for the Payment Account Name
337
- // column. Returning the same field here keeps filter-match parity with the
338
- // visible cell, so any row a user can see is also a row the filter can match.
339
- return transaction.transaction.account?.accountName;
340
- }
341
- case 'payment_account_type': {
342
- // Compare against the raw `paymentType` enum (e.g. "credit_card", "check",
343
- // "cash"). The same enum is what TransactionCategorizationListRow uses for
344
- // its icon switch on line ~1675, and it's what the dropdown options emit
345
- // as `value`. Display labels come from each account's `paymentTypeName`
346
- // field (populated by mapAccountBasePayloadToAccountBase from the backend
347
- // payload) — no client-side label map required.
348
- return transaction.transaction.paymentType;
349
- }
350
- case 'category': {
351
- // Get from transactionLocalData (preferred) or from transaction lines
352
- const localDataForCategory = transaction.transactionLocalData?.transactionReviewLocalData;
353
- if (localDataForCategory) {
354
- // Get category from first line item or most common
355
- const firstLineItem = Object.values(localDataForCategory.lineItemById)[0];
356
- if (firstLineItem?.account?.accountId) {
357
- return firstLineItem.account.accountId;
358
- }
359
- if (firstLineItem?.account?.qboId) {
360
- return firstLineItem.account.qboId;
361
- }
362
- if (firstLineItem?.account?.accountName) {
363
- return firstLineItem.account.accountName;
364
- }
365
- }
366
- // Fallback to transaction lines
367
- const firstLineForCategory = transaction.transaction.lines?.[0];
368
- if (firstLineForCategory?.type ===
369
- 'transaction_with_account_and_class_line' ||
370
- firstLineForCategory?.type ===
371
- 'transaction_with_product_or_service_line' ||
372
- firstLineForCategory?.type === 'journal_entry_transaction_line') {
373
- const account = firstLineForCategory.account;
374
- return account?.accountId ?? account?.qboId ?? account?.accountName;
375
- }
376
- return undefined;
377
- }
378
- case 'class': {
379
- // Similar to category but for class
380
- const localDataForClass = transaction.transactionLocalData?.transactionReviewLocalData;
381
- if (localDataForClass) {
382
- const firstLineItemForClass = Object.values(localDataForClass.lineItemById)[0];
383
- if (firstLineItemForClass?.class?.classId) {
384
- return firstLineItemForClass.class.classId;
385
- }
386
- if (firstLineItemForClass?.class?.qboId) {
387
- return firstLineItemForClass.class.qboId;
388
- }
389
- if (firstLineItemForClass?.class?.className) {
390
- return firstLineItemForClass.class.className;
391
- }
392
- }
393
- const firstLineForClass = transaction.transaction.lines?.[0];
394
- if (firstLineForClass?.type === 'transaction_with_account_and_class_line' ||
395
- firstLineForClass?.type ===
396
- 'transaction_with_product_or_service_line' ||
397
- firstLineForClass?.type === 'journal_entry_transaction_line') {
398
- const classData = firstLineForClass.class;
399
- return classData?.classId ?? classData?.qboId ?? classData?.className;
400
- }
401
- return undefined;
402
- }
403
- default:
404
- return undefined;
405
- }
406
- };
407
237
  const getCategoryValueForPaymentHistory = (key, repayment) => {
408
238
  switch (key) {
409
239
  case 'repaymentDate':
@@ -13,6 +13,7 @@ import { fetchAccountList } from '../../accountList/accountListReducer';
13
13
  import { fetchClassList } from '../../classList/classListReducer';
14
14
  import { getInitializedTransactionVendorLocalData } from '../../commonVendorView/transactionVendorView/transactionVendorLocalDataHelper';
15
15
  import { updateTransactionVendorLocalData } from '../../commonVendorView/transactionVendorView/transactionVendorViewReducer';
16
+ import { fetchTransferAccounts } from '../../expenseAutomationView/reducers/transactionsViewReducer';
16
17
  import { fetchOwnerList } from '../../ownerList/ownerListReducer';
17
18
  import { fetchTransactionDetail, initializeTransactionDetailLocalData, removeTransactionDetail, updateTransactionDetailFetchState, } from '../transactionDetailReducer';
18
19
  import { getAllLinkedTransactions, getTransactionDetailKey, } from '../transactionDetailState';
@@ -34,6 +35,11 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
34
35
  accountList.fetchState !== 'In-Progress') {
35
36
  transactionActions.push(fetchAccountList('accountList'));
36
37
  }
38
+ const { transferAccounts } = state$.value.expenseAutomationTransactionsViewState;
39
+ if (transferAccounts.fetchState !== 'In-Progress' &&
40
+ transferAccounts.fetchState !== 'Completed') {
41
+ transactionActions.push(fetchTransferAccounts());
42
+ }
37
43
  const classList = state$.value.classListState;
38
44
  if (classList.hasValidState() === false &&
39
45
  classList.fetchState !== 'In-Progress') {
@@ -1,5 +1,6 @@
1
1
  import recordGet from 'lodash/get';
2
2
  import { reduceFetchState } from '../../commonStateTypes/reduceFetchState';
3
+ import { getAccountBase, getAccountBaseForTransferAccounts, } from '../../entity/account/accountSelector';
3
4
  import { getIsAccountingClassesEnabled } from '../../entity/tenant/tenantSelector';
4
5
  import { toTransactionTypeStrict } from '../../entity/transaction/stateTypes/transactionType';
5
6
  import { getTransactionWithCOT } from '../../entity/transaction/transactionHelper';
@@ -10,7 +11,7 @@ import { getAccountList, getNestedAccountListHierarchy, } from '../accountList/a
10
11
  import { getClassList, getNestedClassListHierarchy, } from '../classList/classListSelector';
11
12
  import { getAllLinkedTransactions, getTransactionDetailKey, initialSupportedTransactionDetail, } from './transactionDetailState';
12
13
  export const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = true) => {
13
- const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, } = state;
14
+ const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, } = state;
14
15
  const detailKey = getTransactionDetailKey(transactionId);
15
16
  const transactionDetail = recordGet(transactionDetailState.transactionDetailById, detailKey);
16
17
  let fetchState = {
@@ -62,6 +63,14 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
62
63
  : [];
63
64
  const transactionDetailAnyUpdateStatus = reduceUpdateFetchStates(transactionDetail);
64
65
  const vendors = getVendorsByVendorIds(vendorState, vendorListState.vendorIds);
66
+ const transferAccountsFromApi = expenseAutomationTransactionsViewState.transferAccounts.accountIds
67
+ .map((id) => getAccountBaseForTransferAccounts(accountState, id))
68
+ .filter((account) => account != null);
69
+ const transferAccountsList = transferAccountsFromApi.length > 0
70
+ ? transferAccountsFromApi
71
+ : accountsList.accounts
72
+ .map((a) => getAccountBase(accountState, a.accountId, 'account_list'))
73
+ .filter((account) => account != null);
65
74
  return {
66
75
  reportId: 'transaction_detail',
67
76
  reportTitle: 'Transaction Detail',
@@ -78,6 +87,8 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
78
87
  accountsHierarchyList,
79
88
  classList: classList,
80
89
  isAccountingClassesEnabled,
90
+ createTransferEntryStatus: expenseAutomationTransactionsViewState.createTransferEntryStatus,
91
+ transferAccounts: transferAccountsList,
81
92
  isUpdateNotAllowed: transactionDetail?.isUpdateNotAllowed,
82
93
  transactionDetailLocalData: transactionDetail?.transactionDetailLocalData ??
83
94
  initialSupportedTransactionDetail.transactionDetailLocalData,