@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.
- package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
- package/lib/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
- package/lib/entity/account/accountSelector.d.ts +6 -33
- package/lib/entity/account/accountSelector.js +8 -37
- package/lib/entity/account/accountState.d.ts +1 -6
- package/lib/entity/account/accountState.js +4 -11
- package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
- package/lib/entity/class/classReducer.d.ts +4 -4
- package/lib/entity/class/classSelector.d.ts +0 -5
- package/lib/entity/class/classSelector.js +0 -8
- package/lib/entity/class/classState.d.ts +1 -1
- package/lib/entity/forecast/forecastState.d.ts +1 -1
- package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
- package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
- package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
- package/lib/entity/sectionProjectView/sectionProjectView.d.ts +1 -1
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +2 -2
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +2 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +6 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.js +10 -0
- package/lib/entity/transaction/stateTypes/transaction.d.ts +6 -0
- package/lib/epic.d.ts +3 -1
- package/lib/epic.js +3 -1
- package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
- package/lib/esm/entity/account/accountSelector.js +7 -35
- package/lib/esm/entity/account/accountState.js +1 -7
- package/lib/esm/entity/class/classSelector.js +0 -7
- package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
- package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +10 -0
- package/lib/esm/epic.js +3 -1
- package/lib/esm/index.js +14 -15
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.js +81 -0
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +5 -1
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.js +25 -0
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +66 -11
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -57
- package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +15 -185
- package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
- package/lib/esm/view/transactionDetail/transactionDetailSelector.js +12 -1
- package/lib/index.d.ts +20 -20
- package/lib/index.js +51 -49
- package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
- package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
- package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
- package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
- package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
- package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
- package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
- package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.d.ts +9 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/createTransferEntryEpic.js +85 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransferAccountsEpic.js +29 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +16 -6
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +67 -12
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +3 -1
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +3 -4
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -59
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +13 -3
- package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
- package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
- package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
- package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
- package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +4 -45
- package/lib/view/spendManagement/spendManagementFilterHelpers.js +16 -186
- package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
- package/lib/view/topEx/topExSelector.d.ts +1 -1
- package/lib/view/transactionDetail/epics/transactionDetailEpic.d.ts +2 -1
- package/lib/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
- package/lib/view/transactionDetail/transactionDetailPayload.d.ts +1 -1
- package/lib/view/transactionDetail/transactionDetailSelector.d.ts +4 -1
- package/lib/view/transactionDetail/transactionDetailSelector.js +12 -1
- 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
|
|
12
|
-
return
|
|
13
|
-
|
|
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,
|
|
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
|
|
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
|
|
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((
|
|
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:
|
|
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
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
:
|
|
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,
|