@zeniai/client-epic-state 5.1.18-betaDI10 → 5.1.18-betaDI12
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 +3 -1
- package/lib/commonStateTypes/viewAndReport/agingReportStateTypes.d.ts +1 -1
- package/lib/entity/accountRecon/accountReconPayload.d.ts +22 -0
- package/lib/entity/accountRecon/accountReconPayload.js +26 -1
- package/lib/entity/accountRecon/accountReconReducer.d.ts +5 -2
- package/lib/entity/accountRecon/accountReconReducer.js +36 -2
- package/lib/entity/accountRecon/accountReconSelector.d.ts +6 -1
- package/lib/entity/accountRecon/accountReconSelector.js +5 -0
- package/lib/entity/accountRecon/accountReconState.d.ts +22 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.d.ts +8 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +8 -0
- package/lib/entity/task/taskReducer.js +3 -0
- package/lib/entity/task/taskState.d.ts +1 -1
- package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +1 -0
- package/lib/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/entity/transaction/stateTypes/transaction.d.ts +1 -0
- package/lib/epic.d.ts +7 -2
- package/lib/epic.js +7 -2
- package/lib/esm/entity/accountRecon/accountReconPayload.js +26 -1
- package/lib/esm/entity/accountRecon/accountReconReducer.js +35 -1
- package/lib/esm/entity/accountRecon/accountReconSelector.js +5 -0
- package/lib/esm/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
- package/lib/esm/entity/task/taskReducer.js +3 -0
- package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +5 -0
- package/lib/esm/epic.js +7 -2
- package/lib/esm/index.js +9 -9
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +29 -3
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +11 -0
- package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +34 -0
- package/lib/esm/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +34 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +31 -0
- package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +57 -0
- package/lib/esm/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +49 -11
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +30 -3
- package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +153 -0
- package/lib/esm/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +188 -9
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +37 -17
- package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
- package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +27 -0
- package/lib/esm/view/expenseAutomationView/types/reconciliationViewState.js +29 -0
- package/lib/esm/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +4 -16
- package/lib/esm/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
- package/lib/esm/view/opExByVendor/opExByVendorReducer.js +28 -5
- package/lib/esm/view/opExByVendor/opExByVendorSelector.js +1 -0
- package/lib/esm/view/opExByVendor/refreshOpExByVendorReportEpic.js +21 -0
- package/lib/esm/view/referralView/epics/sendReferralInviteEpic.js +9 -1
- package/lib/esm/view/referralView/referralReducer.js +3 -2
- package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +2 -2
- package/lib/esm/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +2 -2
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +3 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +34 -5
- package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/index.d.ts +14 -14
- package/lib/index.js +57 -37
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +14 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +8 -4
- package/lib/view/aiCfoView/aiCfoViewReducer.js +30 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +2 -1
- package/lib/view/aiCfoView/aiCfoViewSelector.js +12 -0
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -0
- package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.d.ts +8 -0
- package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +38 -0
- package/lib/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.d.ts +6 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +38 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.d.ts +26 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +35 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.d.ts +27 -0
- package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +61 -0
- package/lib/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +47 -9
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +30 -3
- package/lib/view/expenseAutomationView/payload/fluxAnalysisPayload.d.ts +8 -0
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +176 -10
- package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +159 -0
- package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +7 -0
- package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.d.ts +2 -1
- package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +53 -3
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +190 -10
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +37 -17
- package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +7 -1
- package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +29 -1
- package/lib/view/expenseAutomationView/types/fluxAnalysisViewState.d.ts +2 -0
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +175 -0
- package/lib/view/expenseAutomationView/types/reconciliationViewState.js +30 -0
- package/lib/view/onboardingView/cockpitView/epic/initializeOnboardingCustomerViewUpdateDataEpic.js +3 -15
- package/lib/view/onboardingView/cockpitView/onboardingCockpitViewPayload.js +2 -2
- package/lib/view/opExByVendor/opExByVendorReducer.d.ts +6 -1
- package/lib/view/opExByVendor/opExByVendorReducer.js +29 -6
- package/lib/view/opExByVendor/opExByVendorSelector.d.ts +1 -0
- package/lib/view/opExByVendor/opExByVendorSelector.js +1 -0
- package/lib/view/opExByVendor/opExByVendorState.d.ts +1 -0
- package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.d.ts +17 -0
- package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.js +25 -0
- package/lib/view/referralView/epics/sendReferralInviteEpic.js +9 -1
- package/lib/view/referralView/referralReducer.d.ts +1 -0
- package/lib/view/referralView/referralReducer.js +4 -3
- package/lib/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +2 -2
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.d.ts +1 -1
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +1 -1
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +1 -1
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
- package/lib/view/taskManager/taskListView/taskListReducer.js +3 -1
- package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +3 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.d.ts +1 -1
- package/lib/view/transactionDetail/epics/saveTransactionHelper.js +11 -2
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.d.ts +8 -0
- package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +36 -6
- package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +17 -0
- package/lib/view/transactionDetail/transactionDetailState.d.ts +1 -0
- package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
- package/lib/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListState.d.ts +1 -1
- package/package.json +5 -2
|
@@ -67,3 +67,156 @@ function createReviewTransactionPayload(accountReconciliationEntity) {
|
|
|
67
67
|
});
|
|
68
68
|
return reviewTransactionsPayload;
|
|
69
69
|
}
|
|
70
|
+
export function isStatementDateConflictResponse(response) {
|
|
71
|
+
return response.status.code === 409 && response.error_code != null;
|
|
72
|
+
}
|
|
73
|
+
function transformStatementUploadPayloadToState(statementUploadPayload) {
|
|
74
|
+
return {
|
|
75
|
+
account: {
|
|
76
|
+
accountId: statementUploadPayload.account.account_id,
|
|
77
|
+
accountName: statementUploadPayload.account.account_name,
|
|
78
|
+
accountType: statementUploadPayload.account.account_type,
|
|
79
|
+
currencyCode: statementUploadPayload.account.currency_code,
|
|
80
|
+
last4Digits: statementUploadPayload.account.last_4_digits,
|
|
81
|
+
},
|
|
82
|
+
file: statementUploadPayload.file != null
|
|
83
|
+
? {
|
|
84
|
+
fileId: statementUploadPayload.file.file_id,
|
|
85
|
+
fileName: statementUploadPayload.file.file_name,
|
|
86
|
+
signedUrl: statementUploadPayload.file.signed_url,
|
|
87
|
+
}
|
|
88
|
+
: null,
|
|
89
|
+
statementMeta: {
|
|
90
|
+
closingBalance: statementUploadPayload.statement_meta.closing_balance,
|
|
91
|
+
openingBalance: statementUploadPayload.statement_meta.opening_balance,
|
|
92
|
+
statementDataStatus: statementUploadPayload.statement_meta.statement_data_status,
|
|
93
|
+
statementEndDate: statementUploadPayload.statement_meta.statement_end_date,
|
|
94
|
+
statementStartDate: statementUploadPayload.statement_meta.statement_start_date,
|
|
95
|
+
statementStatus: statementUploadPayload.statement_meta.statement_status,
|
|
96
|
+
statementUploadId: statementUploadPayload.statement_meta.statement_upload_id,
|
|
97
|
+
totalDeposits: statementUploadPayload.statement_meta.total_deposits,
|
|
98
|
+
totalPayments: statementUploadPayload.statement_meta.total_payments,
|
|
99
|
+
},
|
|
100
|
+
statementTransactions: (statementUploadPayload.statement_transactions ?? []).map((txn) => ({
|
|
101
|
+
amount: txn.amount,
|
|
102
|
+
citations: (txn.citation ?? []).map((c) => ({
|
|
103
|
+
page: c.page,
|
|
104
|
+
pageHeight: c.page_height,
|
|
105
|
+
pageWidth: c.page_width,
|
|
106
|
+
polygon: (c.polygon ?? []).map((point) => ({
|
|
107
|
+
x: point.x,
|
|
108
|
+
y: point.y,
|
|
109
|
+
})),
|
|
110
|
+
referenceText: c.reference_text,
|
|
111
|
+
})),
|
|
112
|
+
isUserAdded: txn.is_user_added,
|
|
113
|
+
isUserEdited: txn.is_user_edited,
|
|
114
|
+
statementTransactionId: txn.statement_transaction_id,
|
|
115
|
+
transactionDate: txn.transaction_date,
|
|
116
|
+
transactionDirection: txn.transaction_direction,
|
|
117
|
+
transactionMemo: txn.transaction_memo,
|
|
118
|
+
})),
|
|
119
|
+
aiSummary: transformAiSummaryPayloadToState(statementUploadPayload.ai_summary),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function transformPreviousReconciliationInfoToState(payload) {
|
|
123
|
+
if (payload == null) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
endDate: payload.end_date,
|
|
128
|
+
reconciledAt: payload.reconciled_at,
|
|
129
|
+
reconciledByUserId: payload.reconciled_by_user_id,
|
|
130
|
+
reconciliationId: payload.reconciliation_id,
|
|
131
|
+
startDate: payload.start_date,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function transformAiSummaryPayloadToState(aiSummaryPayload) {
|
|
135
|
+
if (aiSummaryPayload == null) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const { chain_status: chainStatus } = aiSummaryPayload;
|
|
139
|
+
return {
|
|
140
|
+
accountIdentified: aiSummaryPayload.account_identified,
|
|
141
|
+
transactionsExtracted: aiSummaryPayload.transactions_extracted,
|
|
142
|
+
exceptionsDetected: aiSummaryPayload.exceptions_detected,
|
|
143
|
+
fieldsCaptured: (aiSummaryPayload.fields_captured ?? []).map((field) => ({
|
|
144
|
+
code: field.code,
|
|
145
|
+
label: field.label,
|
|
146
|
+
})),
|
|
147
|
+
chainStatus: {
|
|
148
|
+
code: chainStatus?.code ?? '',
|
|
149
|
+
label: chainStatus?.label ?? '',
|
|
150
|
+
expectedStartDate: chainStatus?.expected_start_date ?? null,
|
|
151
|
+
previousReconciliationInfo: transformPreviousReconciliationInfoToState(chainStatus?.previous_reconciliation_info),
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Builds date-conflict state from a 409 Confirm & Save response.
|
|
157
|
+
* Returns null for non-409 responses or 409s without a recognized error code.
|
|
158
|
+
*/
|
|
159
|
+
export function transformStatementDateConflictToState(response) {
|
|
160
|
+
if (isStatementDateConflictResponse(response) === false) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
const previousReconciliationInfo = transformPreviousReconciliationInfoToState(response.previous_reconciliation_info);
|
|
164
|
+
if (response.error_code === 'STATEMENT_RANGE_ALREADY_RECONCILED' &&
|
|
165
|
+
previousReconciliationInfo == null) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
if (response.error_code === 'STATEMENT_RANGE_HAS_GAP' &&
|
|
169
|
+
response.expected_start_date == null &&
|
|
170
|
+
previousReconciliationInfo == null) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
errorCode: response.error_code,
|
|
175
|
+
expectedStartDate: response.expected_start_date ?? null,
|
|
176
|
+
...(previousReconciliationInfo != null ? { previousReconciliationInfo } : {}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
export function transformParseStatementPayloadToState(payload) {
|
|
180
|
+
return {
|
|
181
|
+
statementUpload: transformStatementUploadPayloadToState(payload.statement_upload),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export function transformUpdateStatementInfoPayloadToState(payload) {
|
|
185
|
+
return {
|
|
186
|
+
statementUpload: transformStatementUploadPayloadToState(payload.statement_upload),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
export function transformStatementUpdateStateToPayload(localData) {
|
|
190
|
+
const { statementMeta, statementTransactions } = localData;
|
|
191
|
+
return {
|
|
192
|
+
statement_meta: {
|
|
193
|
+
opening_balance: statementMeta.openingBalance,
|
|
194
|
+
statement_end_date: statementMeta.statementEndDate,
|
|
195
|
+
statement_start_date: statementMeta.statementStartDate,
|
|
196
|
+
total_deposits: statementMeta.totalDeposits,
|
|
197
|
+
total_payments: statementMeta.totalPayments,
|
|
198
|
+
},
|
|
199
|
+
statement_transactions: {
|
|
200
|
+
added: statementTransactions.added.map((txn) => ({
|
|
201
|
+
amount: txn.amount,
|
|
202
|
+
transaction_date: txn.transactionDate,
|
|
203
|
+
transaction_direction: txn.transactionDirection,
|
|
204
|
+
transaction_memo: txn.transactionMemo,
|
|
205
|
+
})),
|
|
206
|
+
deleted_ids: statementTransactions.deletedIds,
|
|
207
|
+
updated: statementTransactions.updated
|
|
208
|
+
.filter((txn) => txn.statementTransactionId != null)
|
|
209
|
+
.map((txn) => ({
|
|
210
|
+
amount: txn.amount,
|
|
211
|
+
statement_transaction_id: txn.statementTransactionId,
|
|
212
|
+
transaction_date: txn.transactionDate,
|
|
213
|
+
transaction_direction: txn.transactionDirection,
|
|
214
|
+
transaction_memo: txn.transactionMemo,
|
|
215
|
+
})),
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/** API request body for PUT statement-uploads; cast lives here for putAndGetJSON. */
|
|
220
|
+
export function toStatementUpdateRequestBody(localData) {
|
|
221
|
+
return transformStatementUpdateStateToPayload(localData);
|
|
222
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
3
3
|
import { defaultVendorCurrency } from '../../../entity/vendor/vendorState';
|
|
4
|
+
import { date } from '../../../zeniDayJS';
|
|
4
5
|
import { toBalancesByMonthFromPayload, toVendorFluxAnalysisStatusFromPayload, } from '../helpers/helpers';
|
|
5
6
|
export const initialState = {
|
|
6
7
|
fluxAnalysisEntities: { operatingExpenses: [] },
|
|
@@ -31,6 +32,7 @@ export const initialState = {
|
|
|
31
32
|
fetchState: 'Not-Started',
|
|
32
33
|
error: undefined,
|
|
33
34
|
currency: defaultVendorCurrency,
|
|
35
|
+
lastRefreshSuccessTime: undefined,
|
|
34
36
|
totalBalancesAndVariance: undefined,
|
|
35
37
|
hasValidState() {
|
|
36
38
|
return this.fetchState == 'Completed';
|
|
@@ -99,7 +101,7 @@ const expenseAutomationFluxAnalysisView = createSlice({
|
|
|
99
101
|
},
|
|
100
102
|
},
|
|
101
103
|
fetchFluxAnalysisViewSuccess(draft, action) {
|
|
102
|
-
const { expensesPayload, selectedPeriod, keepExistingListItems, fetchReimbursement, currency, totalsPayload, } = action.payload;
|
|
104
|
+
const { expensesPayload, selectedPeriod, keepExistingListItems, fetchReimbursement, currency, status, totalsPayload, } = action.payload;
|
|
103
105
|
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
104
106
|
const group = draft.groupsBySelectedPeriod[periodId];
|
|
105
107
|
const groupToBeFetched = fetchReimbursement
|
|
@@ -109,6 +111,9 @@ const expenseAutomationFluxAnalysisView = createSlice({
|
|
|
109
111
|
// Handle fetch completion
|
|
110
112
|
handleFetchCompletion(draft, selectedPeriod, fetchReimbursement, groupToBeFetched);
|
|
111
113
|
draft.fetchState = 'Completed';
|
|
114
|
+
if (status?.last_refresh_success_time != null) {
|
|
115
|
+
draft.lastRefreshSuccessTime = date(status.last_refresh_success_time);
|
|
116
|
+
}
|
|
112
117
|
// Update flux analysis entities
|
|
113
118
|
const allFluxAnalysisEntities = updateFluxAnalysisEntities(draft.fluxAnalysisEntities, expensesPayload, currency);
|
|
114
119
|
// Update operating expense ids based on the "keepExistingListItems" flag
|
|
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
3
3
|
import { toReconciliationAccountSource } from '../../../entity/account/accountState';
|
|
4
4
|
import { toBankStatusCodeType } from '../../../entity/accountRecon/accountReconState';
|
|
5
|
+
import { toReconciliationViewSummary, } from '../types/reconciliationViewState';
|
|
5
6
|
// Initial state
|
|
6
7
|
export const initialReconciliationTabsState = {
|
|
7
8
|
balances: {
|
|
@@ -67,6 +68,7 @@ export const initialState = {
|
|
|
67
68
|
refreshStatus: { fetchState: 'Not-Started', error: undefined },
|
|
68
69
|
actionFetchState: initialActionFetchState,
|
|
69
70
|
selectedAccountId: undefined,
|
|
71
|
+
statementProcessingFailed: false,
|
|
70
72
|
statementUploadChosen: false,
|
|
71
73
|
reconListUIState: {
|
|
72
74
|
nodeCollapseState: {},
|
|
@@ -75,6 +77,7 @@ export const initialState = {
|
|
|
75
77
|
},
|
|
76
78
|
},
|
|
77
79
|
excludedAccountIDs: [],
|
|
80
|
+
summary: undefined,
|
|
78
81
|
};
|
|
79
82
|
// Create slice with reducers
|
|
80
83
|
const expenseAutomationReconciliationView = createSlice({
|
|
@@ -143,7 +146,7 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
143
146
|
fetchReconciliationSuccess: {
|
|
144
147
|
reducer(draft, action) {
|
|
145
148
|
if (action.payload.accountId == null) {
|
|
146
|
-
updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? []);
|
|
149
|
+
updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? [], action.payload.reconciliation.summary);
|
|
147
150
|
}
|
|
148
151
|
else if (action.payload.reconciliation.reconciliation.length > 0 &&
|
|
149
152
|
action.payload.reconciliation.accounts.length > 0) {
|
|
@@ -287,6 +290,10 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
287
290
|
updateSelectedDrawerAccountId: (draft, action) => {
|
|
288
291
|
draft.selectedDrawerAccountId = action.payload.selectedDrawerAccountId;
|
|
289
292
|
},
|
|
293
|
+
updateStatementProcessingFailed: (draft, action) => {
|
|
294
|
+
draft.statementProcessingFailed =
|
|
295
|
+
action.payload.statementProcessingFailed;
|
|
296
|
+
},
|
|
290
297
|
initialiseLocalDataForSelectedAccountId: () => { },
|
|
291
298
|
updateSelectedTab: (draft, action) => {
|
|
292
299
|
const { selectedTab } = action.payload;
|
|
@@ -378,10 +385,22 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
378
385
|
},
|
|
379
386
|
uploadAccountStatement: (draft, action) => {
|
|
380
387
|
const { accountId, selectedPeriod } = action.payload;
|
|
381
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
388
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
389
|
+
if (accountRecon != null) {
|
|
390
|
+
accountRecon.statementUploadStatus = {
|
|
391
|
+
fetchState: 'In-Progress',
|
|
392
|
+
error: undefined,
|
|
393
|
+
};
|
|
394
|
+
accountRecon.parsedStatementData = undefined;
|
|
395
|
+
accountRecon.statementParseStatus = {
|
|
396
|
+
fetchState: 'Not-Started',
|
|
397
|
+
error: undefined,
|
|
398
|
+
};
|
|
399
|
+
accountRecon.reparseStatementStatus = {
|
|
400
|
+
fetchState: 'Not-Started',
|
|
401
|
+
error: undefined,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
385
404
|
},
|
|
386
405
|
uploadAccountStatementSuccess: (draft, action) => {
|
|
387
406
|
const { accountId, selectedPeriod } = action.payload;
|
|
@@ -419,6 +438,143 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
419
438
|
error: action.payload.error,
|
|
420
439
|
};
|
|
421
440
|
},
|
|
441
|
+
parseStatement: (draft, action) => {
|
|
442
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
443
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
444
|
+
if (accountRecon != null) {
|
|
445
|
+
accountRecon.parsedStatementData = undefined;
|
|
446
|
+
accountRecon.statementParseStatus = {
|
|
447
|
+
fetchState: 'In-Progress',
|
|
448
|
+
error: undefined,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
parseStatementSuccess: (draft, action) => {
|
|
453
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
454
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseStatus = {
|
|
455
|
+
fetchState: 'Completed',
|
|
456
|
+
error: undefined,
|
|
457
|
+
};
|
|
458
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = false;
|
|
459
|
+
draft.statementProcessingFailed = false;
|
|
460
|
+
},
|
|
461
|
+
parseStatementFailure: (draft, action) => {
|
|
462
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
463
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseStatus = {
|
|
464
|
+
fetchState: 'Error',
|
|
465
|
+
error: action.payload.error,
|
|
466
|
+
};
|
|
467
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = false;
|
|
468
|
+
draft.statementProcessingFailed = true;
|
|
469
|
+
},
|
|
470
|
+
reparseStatement: (draft, action) => {
|
|
471
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
472
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
473
|
+
if (accountRecon != null) {
|
|
474
|
+
accountRecon.parsedStatementData = undefined;
|
|
475
|
+
accountRecon.reparseStatementStatus = {
|
|
476
|
+
fetchState: 'In-Progress',
|
|
477
|
+
error: undefined,
|
|
478
|
+
};
|
|
479
|
+
accountRecon.statementParseStatus = {
|
|
480
|
+
fetchState: 'Not-Started',
|
|
481
|
+
error: undefined,
|
|
482
|
+
};
|
|
483
|
+
accountRecon.statementParseInProgress = false;
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
reparseStatementSuccess: (draft, action) => {
|
|
487
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
488
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
|
|
489
|
+
fetchState: 'Completed',
|
|
490
|
+
error: undefined,
|
|
491
|
+
};
|
|
492
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseStatus = {
|
|
493
|
+
fetchState: 'Not-Started',
|
|
494
|
+
error: undefined,
|
|
495
|
+
};
|
|
496
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = false;
|
|
497
|
+
draft.statementProcessingFailed = false;
|
|
498
|
+
},
|
|
499
|
+
reparseStatementFailure: (draft, action) => {
|
|
500
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
501
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
|
|
502
|
+
fetchState: 'Error',
|
|
503
|
+
error: action.payload.error,
|
|
504
|
+
};
|
|
505
|
+
draft.statementProcessingFailed = true;
|
|
506
|
+
},
|
|
507
|
+
resetReparseStatementStatus: (draft, action) => {
|
|
508
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
509
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
|
|
510
|
+
fetchState: 'Not-Started',
|
|
511
|
+
error: undefined,
|
|
512
|
+
};
|
|
513
|
+
},
|
|
514
|
+
updateParsedStatementData: (draft, action) => {
|
|
515
|
+
const { accountId, selectedPeriod, parsedStatementData } = action.payload;
|
|
516
|
+
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].parsedStatementData =
|
|
517
|
+
parsedStatementData;
|
|
518
|
+
},
|
|
519
|
+
updateStatementUpdateLocalData: (draft, action) => {
|
|
520
|
+
const { accountId, selectedPeriod, statementUpdateLocalData } = action.payload;
|
|
521
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
522
|
+
if (accountRecon != null) {
|
|
523
|
+
if (accountRecon.localData == null) {
|
|
524
|
+
accountRecon.localData = {
|
|
525
|
+
statementUpdateLocalData,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
accountRecon.localData.statementUpdateLocalData =
|
|
530
|
+
statementUpdateLocalData;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
submitStatementUpdate: (draft, action) => {
|
|
535
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
536
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
537
|
+
if (accountRecon != null) {
|
|
538
|
+
accountRecon.statementUpdateStatus = {
|
|
539
|
+
fetchState: 'In-Progress',
|
|
540
|
+
error: undefined,
|
|
541
|
+
};
|
|
542
|
+
// Clear any stale date conflict from a previous attempt.
|
|
543
|
+
accountRecon.statementDateConflict = null;
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
submitStatementUpdateSuccess: (draft, action) => {
|
|
547
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
548
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
549
|
+
if (accountRecon != null) {
|
|
550
|
+
accountRecon.statementUpdateStatus = {
|
|
551
|
+
fetchState: 'Completed',
|
|
552
|
+
error: undefined,
|
|
553
|
+
};
|
|
554
|
+
accountRecon.statementDateConflict = null;
|
|
555
|
+
if (accountRecon.localData != null) {
|
|
556
|
+
accountRecon.localData.statementUpdateLocalData = undefined;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
submitStatementUpdateFailure: (draft, action) => {
|
|
561
|
+
const { accountId, selectedPeriod, dateConflict } = action.payload;
|
|
562
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
563
|
+
if (accountRecon != null) {
|
|
564
|
+
accountRecon.statementUpdateStatus = {
|
|
565
|
+
fetchState: 'Error',
|
|
566
|
+
error: action.payload.error,
|
|
567
|
+
};
|
|
568
|
+
accountRecon.statementDateConflict = dateConflict ?? null;
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
clearStatementDateConflict: (draft, action) => {
|
|
572
|
+
const { accountId, selectedPeriod } = action.payload;
|
|
573
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
574
|
+
if (accountRecon != null) {
|
|
575
|
+
accountRecon.statementDateConflict = null;
|
|
576
|
+
}
|
|
577
|
+
},
|
|
422
578
|
updateAccountReconciliationLocalData: (draft, action) => {
|
|
423
579
|
const { accountId, selectedPeriod, localData } = action.payload;
|
|
424
580
|
const oldLocalData = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData;
|
|
@@ -524,10 +680,10 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
524
680
|
},
|
|
525
681
|
});
|
|
526
682
|
// Export actions
|
|
527
|
-
export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
|
|
683
|
+
export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateStatementProcessingFailed, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateStatementUpdateLocalData, submitStatementUpdate, submitStatementUpdateSuccess, submitStatementUpdateFailure, clearStatementDateConflict, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
|
|
528
684
|
// Export reducer
|
|
529
685
|
export default expenseAutomationReconciliationView.reducer;
|
|
530
|
-
function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts) {
|
|
686
|
+
function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts, summary) {
|
|
531
687
|
draft.excludedAccountIDs = excludedAccounts.map((ea) => ea.account_id);
|
|
532
688
|
draft.excludedAccountExclusionInfo = {};
|
|
533
689
|
excludedAccounts.forEach((ea) => {
|
|
@@ -556,6 +712,7 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
|
|
|
556
712
|
: undefined,
|
|
557
713
|
};
|
|
558
714
|
});
|
|
715
|
+
const oldReconciliationByAccountID = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID ?? {};
|
|
559
716
|
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)] = {
|
|
560
717
|
accountIDs: [],
|
|
561
718
|
reconciliationByAccountID: {},
|
|
@@ -579,6 +736,7 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
|
|
|
579
736
|
paymentAccountId: account?.payment_account_id ?? undefined,
|
|
580
737
|
};
|
|
581
738
|
}
|
|
739
|
+
const oldRecord = oldReconciliationByAccountID[reconciliation.account_id];
|
|
582
740
|
accountReconciliationRecords.reconciliationByAccountID[reconciliation.account_id] = {
|
|
583
741
|
accountId: reconciliation.account_id,
|
|
584
742
|
reconciliationId: reconciliation.reconciliation_id ?? undefined,
|
|
@@ -586,16 +744,30 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
|
|
|
586
744
|
refreshStatus: { fetchState: 'Not-Started', error: undefined },
|
|
587
745
|
statementDeleteStatus: { fetchState: 'Not-Started', error: undefined },
|
|
588
746
|
statementUploadStatus: { fetchState: 'Not-Started', error: undefined },
|
|
589
|
-
statementUpdateStatus:
|
|
747
|
+
statementUpdateStatus: oldRecord?.statementUpdateStatus ?? {
|
|
748
|
+
fetchState: 'Not-Started',
|
|
749
|
+
error: undefined,
|
|
750
|
+
},
|
|
590
751
|
statementParseInProgress: reconciliation.bank_status.code === 'parsing',
|
|
752
|
+
statementParseStatus: oldRecord?.statementParseStatus ?? {
|
|
753
|
+
fetchState: 'Not-Started',
|
|
754
|
+
error: undefined,
|
|
755
|
+
},
|
|
756
|
+
reparseStatementStatus: oldRecord?.reparseStatementStatus ?? {
|
|
757
|
+
fetchState: 'Not-Started',
|
|
758
|
+
error: undefined,
|
|
759
|
+
},
|
|
760
|
+
statementDateConflict: oldRecord?.statementDateConflict ?? null,
|
|
591
761
|
localData: {
|
|
762
|
+
...oldRecord?.localData,
|
|
592
763
|
accountSource: account?.reconciliation_source != null
|
|
593
764
|
? toReconciliationAccountSource(account.reconciliation_source)
|
|
594
|
-
:
|
|
765
|
+
: oldRecord?.localData?.accountSource,
|
|
595
766
|
},
|
|
596
767
|
accountDetectionReason: account?.detection_info != null && account.detection_reason != null
|
|
597
768
|
? account.detection_reason
|
|
598
769
|
: undefined,
|
|
770
|
+
parsedStatementData: oldRecord?.parsedStatementData,
|
|
599
771
|
};
|
|
600
772
|
accountReconciliationRecords.accountIDs.push(reconciliation.account_id);
|
|
601
773
|
});
|
|
@@ -609,6 +781,10 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
|
|
|
609
781
|
draft.fetchState = 'Completed';
|
|
610
782
|
draft.error = undefined;
|
|
611
783
|
}
|
|
784
|
+
if (summary !== undefined) {
|
|
785
|
+
draft.summary =
|
|
786
|
+
summary != null ? toReconciliationViewSummary(summary) : undefined;
|
|
787
|
+
}
|
|
612
788
|
}
|
|
613
789
|
function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accountId, reconciliationData, refreshViewInBackground) {
|
|
614
790
|
const oldRecord = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId];
|
|
@@ -676,6 +852,9 @@ const updateReconciliationByAccountIDOnIncludeAccount = (draft, accountId, recon
|
|
|
676
852
|
statementUploadStatus: { fetchState: 'Not-Started', error: undefined },
|
|
677
853
|
statementUpdateStatus: { fetchState: 'Not-Started', error: undefined },
|
|
678
854
|
statementParseInProgress: reconciliation.bank_status.code === 'parsing',
|
|
855
|
+
statementParseStatus: { fetchState: 'Not-Started', error: undefined },
|
|
856
|
+
reparseStatementStatus: { fetchState: 'Not-Started', error: undefined },
|
|
857
|
+
statementDateConflict: null,
|
|
679
858
|
localData: {},
|
|
680
859
|
accountDetectionReason: undefined,
|
|
681
860
|
};
|
|
@@ -153,27 +153,39 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
153
153
|
draft.transactionCategorizationView[selectedTab].fetchState =
|
|
154
154
|
'In-Progress';
|
|
155
155
|
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
156
|
+
// A foreground fetch supersedes any in-flight background preload.
|
|
157
|
+
// Reset refreshStatus so a cancelled preload doesn't leave the
|
|
158
|
+
// spinner stuck at In-Progress.
|
|
159
|
+
draft.transactionCategorizationView[selectedTab].refreshStatus = {
|
|
160
|
+
fetchState: 'Not-Started',
|
|
161
|
+
error: undefined,
|
|
162
|
+
};
|
|
156
163
|
}
|
|
157
164
|
draft.transactionCategorizationView[selectedTab].uiState.pageToken =
|
|
158
165
|
pageToken ?? null;
|
|
159
|
-
|
|
160
|
-
|
|
166
|
+
// Only overwrite when explicitly set; undefined means a non-search fetch
|
|
167
|
+
// (tab switch, period change) should preserve the existing search string.
|
|
168
|
+
if (searchString !== undefined) {
|
|
169
|
+
draft.transactionCategorizationView[selectedTab].uiState.searchString =
|
|
170
|
+
searchString;
|
|
171
|
+
}
|
|
161
172
|
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
173
|
+
const monthYearPeriod = {
|
|
174
|
+
month: period.start.month,
|
|
175
|
+
year: period.start.year,
|
|
176
|
+
};
|
|
177
|
+
const periodId = toMonthYearPeriodId(monthYearPeriod);
|
|
178
|
+
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
179
|
+
.transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
162
180
|
// Reset list when we change the sort order and fetch list again
|
|
163
181
|
if (resetListItems === true) {
|
|
164
|
-
const monthYearPeriod = {
|
|
165
|
-
month: period.start.month,
|
|
166
|
-
year: period.start.year,
|
|
167
|
-
};
|
|
168
|
-
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
169
|
-
.transactionIdsBySelectedPeriod[toMonthYearPeriodId(monthYearPeriod)];
|
|
170
182
|
transactionIdsBySelectedPeriod.forEach((transactionId) => {
|
|
171
183
|
delete draft.transactionCategorizationView[selectedTab]
|
|
172
184
|
.transactionReviewLocalDataById[transactionId];
|
|
173
185
|
});
|
|
174
186
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds =
|
|
175
187
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds.filter((selectedCheckBoxTransactionId) => transactionIdsBySelectedPeriod.includes(selectedCheckBoxTransactionId));
|
|
176
|
-
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[
|
|
188
|
+
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[periodId] = [];
|
|
177
189
|
draft.transactionCategorizationView[selectedTab].refreshStatus = {
|
|
178
190
|
fetchState: 'Not-Started',
|
|
179
191
|
error: undefined,
|
|
@@ -305,10 +317,12 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
305
317
|
}
|
|
306
318
|
},
|
|
307
319
|
updateTransactionFilters(draft, action) {
|
|
308
|
-
const {
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
|
|
320
|
+
const { filters } = action.payload;
|
|
321
|
+
// Filters are tab-agnostic (payee/category/class/amount), so apply to
|
|
322
|
+
// all tabs so switching tabs after filtering shows consistent results.
|
|
323
|
+
TRANSACTIONS_TABS.forEach((tab) => {
|
|
324
|
+
draft.transactionCategorizationView[tab].filters = filters;
|
|
325
|
+
});
|
|
312
326
|
},
|
|
313
327
|
saveTransactionCategorization: {
|
|
314
328
|
prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
|
|
@@ -660,18 +674,24 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
660
674
|
resetOtherTabsFetchState(draft, action) {
|
|
661
675
|
const { tabs, refreshViewInBackground } = action.payload;
|
|
662
676
|
tabs.forEach((tab) => {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
677
|
+
const tabFetchState = draft.transactionCategorizationView[tab].fetchState;
|
|
678
|
+
if (refreshViewInBackground !== true) {
|
|
679
|
+
// Foreground fetch completed: mark other tabs as Completed.
|
|
666
680
|
draft.transactionCategorizationView[tab].fetchState = 'Completed';
|
|
667
681
|
draft.transactionCategorizationView[tab].error = undefined;
|
|
668
682
|
}
|
|
669
|
-
else {
|
|
683
|
+
else if (tabFetchState !== 'In-Progress') {
|
|
684
|
+
// Background fetch completed: reset the other tab's refreshStatus,
|
|
685
|
+
// but only when it is not mid-load. During a dual-search the active
|
|
686
|
+
// tab has its own foreground fetch in flight — clobbering its
|
|
687
|
+
// fetchState here would drop the skeleton and show an empty list.
|
|
670
688
|
draft.transactionCategorizationView[tab].refreshStatus = {
|
|
671
689
|
fetchState: 'Not-Started',
|
|
672
690
|
error: undefined,
|
|
673
691
|
};
|
|
674
692
|
}
|
|
693
|
+
// If tabFetchState === 'In-Progress' and refreshViewInBackground === true,
|
|
694
|
+
// leave the other tab's state untouched — it has its own active fetch.
|
|
675
695
|
});
|
|
676
696
|
},
|
|
677
697
|
fetchTransactionCategorizationFailure(draft, action) {
|
|
@@ -8,7 +8,7 @@ import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
|
8
8
|
import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
|
|
9
9
|
export function getExpenseAutomationFluxAnalysisView(state) {
|
|
10
10
|
const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
|
|
11
|
-
const { fetchState, error, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
|
|
11
|
+
const { fetchState, error, lastRefreshSuccessTime, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
|
|
12
12
|
const fetchStateAndError = {
|
|
13
13
|
fetchState,
|
|
14
14
|
error,
|
|
@@ -110,6 +110,7 @@ export function getExpenseAutomationFluxAnalysisView(state) {
|
|
|
110
110
|
refreshStatus,
|
|
111
111
|
currency,
|
|
112
112
|
completionStatus,
|
|
113
|
+
lastRefreshSuccessTime,
|
|
113
114
|
};
|
|
114
115
|
}
|
|
115
116
|
// Helper function to transform operating expense to vendor view
|