@zeniai/client-epic-state 5.1.58 → 5.1.60-beta0ND

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 (69) hide show
  1. package/lib/entity/accountRecon/accountReconPayload.d.ts +1 -1
  2. package/lib/entity/accountRecon/accountReconReducer.js +15 -1
  3. package/lib/epic.d.ts +2 -1
  4. package/lib/epic.js +2 -1
  5. package/lib/esm/entity/accountRecon/accountReconReducer.js +15 -1
  6. package/lib/esm/epic.js +2 -1
  7. package/lib/esm/index.js +3 -4
  8. package/lib/esm/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +0 -1
  9. package/lib/esm/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.js +1 -2
  10. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +3 -3
  11. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +2 -3
  12. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +2 -2
  13. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  14. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -4
  15. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +2 -4
  16. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/markTransactionAsNotMiscategorizedEpic.js +2 -2
  17. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/saveTransactionCategorizationEpic.js +2 -2
  18. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/triggerReviewTabRefetchEpic.js +2 -2
  19. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/updateTransactionCategorizationEpic.js +2 -2
  20. package/lib/esm/view/expenseAutomationView/expenseAutomationViewReducer.js +3 -4
  21. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +14 -25
  22. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +21 -32
  23. package/lib/esm/view/expenseAutomationView/selectors/statementParseViewSelector.js +0 -224
  24. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewSelector.js +2 -1
  25. package/lib/esm/view/recommendation/fetchEntityRecommendationsByTransactionIdEpic.js +2 -2
  26. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +2 -2
  27. package/lib/esm/view/recommendation/recommendationReducer.js +18 -3
  28. package/lib/esm/view/recommendation/submitRecommendationFeedbackEpic.js +51 -0
  29. package/lib/esm/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -2
  30. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +2 -2
  31. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -2
  32. package/lib/index.d.ts +4 -5
  33. package/lib/index.js +39 -42
  34. package/lib/view/commonVendorView/transactionVendorView/epics/saveTransactionVendorEpic.js +0 -1
  35. package/lib/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.d.ts +1 -2
  36. package/lib/view/commonVendorView/transactionVendorView/transactionVendorViewReducer.js +1 -2
  37. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +3 -3
  38. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +2 -3
  39. package/lib/view/expenseAutomationView/epics/transactionCategorization/backgroundRefetchReviewTabEpic.js +2 -2
  40. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +1 -1
  41. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +4 -4
  42. package/lib/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +2 -4
  43. package/lib/view/expenseAutomationView/epics/transactionCategorization/markTransactionAsNotMiscategorizedEpic.js +2 -2
  44. package/lib/view/expenseAutomationView/epics/transactionCategorization/saveTransactionCategorizationEpic.js +2 -2
  45. package/lib/view/expenseAutomationView/epics/transactionCategorization/triggerReviewTabRefetchEpic.js +2 -2
  46. package/lib/view/expenseAutomationView/epics/transactionCategorization/updateTransactionCategorizationEpic.js +2 -2
  47. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.d.ts +2 -5
  48. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.js +3 -4
  49. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +5 -5
  50. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +14 -25
  51. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +10 -23
  52. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +21 -32
  53. package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.d.ts +1 -15
  54. package/lib/view/expenseAutomationView/selectors/statementParseViewSelector.js +1 -233
  55. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +7 -44
  56. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.d.ts +1 -0
  57. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.js +2 -1
  58. package/lib/view/recommendation/fetchEntityRecommendationsByTransactionIdEpic.js +2 -2
  59. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +2 -2
  60. package/lib/view/recommendation/recommendationPayload.d.ts +33 -0
  61. package/lib/view/recommendation/recommendationReducer.d.ts +3 -4
  62. package/lib/view/recommendation/recommendationReducer.js +19 -4
  63. package/lib/view/recommendation/submitRecommendationFeedbackEpic.d.ts +7 -0
  64. package/lib/view/recommendation/submitRecommendationFeedbackEpic.js +55 -0
  65. package/lib/view/transactionDetail/epics/saveTransactionDetailEpic.js +2 -2
  66. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +2 -2
  67. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +1 -3
  68. package/lib/view/transactionDetail/transactionDetailReducer.js +1 -2
  69. package/package.json +1 -1
@@ -64,117 +64,6 @@ export const getDateFilteredDeletedTransactionIds = (allParsedTransactions, stat
64
64
  !isStatementTransactionInPeriod(transaction.transactionDate, statementPeriod.statementStartDate, statementPeriod.statementEndDate))
65
65
  .map((transaction) => transaction.statementTransactionId);
66
66
  };
67
- const roundCurrency = (value) => Math.round(value * 100) / 100;
68
- const toApiDateString = (value) => {
69
- if (value == null || value === '') {
70
- return '';
71
- }
72
- return date(value).format('YYYY-MM-DD');
73
- };
74
- const computeStatementTransactionTotals = (transactions) => {
75
- const totalDeposits = roundCurrency(transactions
76
- .filter((txn) => txn.transactionDirection === 'credit')
77
- .reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
78
- const totalPayments = roundCurrency(transactions
79
- .filter((txn) => txn.transactionDirection === 'debit')
80
- .reduce((sum, txn) => sum + Math.abs(txn.amount ?? 0), 0));
81
- return { totalDeposits, totalPayments };
82
- };
83
- const computeStatementClosingBalance = (openingBalance, totalDeposits, totalPayments, accountType) => roundCurrency(accountType === 'credit_card'
84
- ? openingBalance + totalPayments - totalDeposits
85
- : openingBalance + totalDeposits - totalPayments);
86
- const filterFormTransactionsInPeriod = (transactions, statementStartDate, statementEndDate) => {
87
- if (statementStartDate === '' || statementEndDate === '') {
88
- return transactions;
89
- }
90
- const periodStart = date(statementStartDate).startOf('day');
91
- const periodEnd = date(statementEndDate).startOf('day');
92
- return transactions.filter((txn) => {
93
- if (txn.transactionDate === '') {
94
- return true;
95
- }
96
- const txnDate = date(txn.transactionDate).startOf('day');
97
- return (txnDate.isSameOrAfter(periodStart, 'day') &&
98
- txnDate.isSameOrBefore(periodEnd, 'day'));
99
- });
100
- };
101
- export const isStatementParseTransactionFieldChange = (changedField) => changedField === 'transactions' ||
102
- changedField?.startsWith('transactions.') === true;
103
- const isStatementParseBalanceAffectingTransactionFieldChange = (changedField) => {
104
- if (changedField === 'transactions') {
105
- return true;
106
- }
107
- if (changedField?.startsWith('transactions.') !== true) {
108
- return false;
109
- }
110
- return !changedField.endsWith('.transactionMemo');
111
- };
112
- export const isStatementParseManualBalanceField = (field) => field === 'totalDeposits' ||
113
- field === 'totalPayments' ||
114
- field === 'closingBalance';
115
- export const shouldRecalculateStatementParseBalances = (changedField) => isStatementParseBalanceAffectingTransactionFieldChange(changedField) ||
116
- changedField === 'statementStartDate' ||
117
- changedField === 'statementEndDate';
118
- export const resolveStatementParseBalanceFields = (formView, changedField, accountType) => {
119
- const inPeriodTransactions = filterFormTransactionsInPeriod(formView.transactions, formView.statementStartDate, formView.statementEndDate);
120
- const { totalDeposits, totalPayments } = computeStatementTransactionTotals(inPeriodTransactions);
121
- if (!shouldRecalculateStatementParseBalances(changedField)) {
122
- return {
123
- openingBalance: formView.openingBalance,
124
- closingBalance: formView.closingBalance,
125
- totalDeposits: formView.totalDeposits,
126
- totalPayments: formView.totalPayments,
127
- };
128
- }
129
- return {
130
- openingBalance: formView.openingBalance,
131
- totalDeposits,
132
- totalPayments,
133
- closingBalance: computeStatementClosingBalance(formView.openingBalance, totalDeposits, totalPayments, accountType),
134
- };
135
- };
136
- export const areStatementParseBalancesConsistent = (formView, accountType) => {
137
- // Validate the four balance fields against each other (what the user sees),
138
- // not against recomputed transaction totals. Manual deposits/payments edits
139
- // are allowed as long as closing matches the account-type formula.
140
- return (roundCurrency(formView.closingBalance) ===
141
- computeStatementClosingBalance(formView.openingBalance, formView.totalDeposits, formView.totalPayments, accountType));
142
- };
143
- const mapParsedTransactionToFormRow = (transaction, index) => ({
144
- id: transaction.statementTransactionId || `parsed-${index}`,
145
- transactionDate: toApiDateString(transaction.transactionDate),
146
- transactionMemo: transaction.transactionMemo,
147
- amount: transaction.amount,
148
- transactionDirection: transaction.transactionDirection,
149
- statementTransactionId: transaction.statementTransactionId,
150
- });
151
- const mapLocalTransactionToFormRow = (transaction, id) => ({
152
- id,
153
- transactionDate: toApiDateString(transaction.transactionDate),
154
- transactionMemo: transaction.transactionMemo,
155
- amount: transaction.amount,
156
- transactionDirection: transaction.transactionDirection,
157
- statementTransactionId: transaction.statementTransactionId,
158
- });
159
- const buildStatementParseFormTransactions = (originalTransactions, localData) => {
160
- const deletedIdSet = new Set(localData.statementTransactions?.deletedIds ?? []);
161
- const updatedById = new Map((localData.statementTransactions?.updated ?? [])
162
- .filter((transaction) => transaction.statementTransactionId != null)
163
- .map((transaction) => [
164
- transaction.statementTransactionId,
165
- transaction,
166
- ]));
167
- const persistedTransactions = originalTransactions
168
- .filter((transaction) => !deletedIdSet.has(transaction.statementTransactionId))
169
- .map((transaction, index) => {
170
- const updated = updatedById.get(transaction.statementTransactionId);
171
- return updated != null
172
- ? mapLocalTransactionToFormRow(updated, transaction.statementTransactionId)
173
- : mapParsedTransactionToFormRow(transaction, index);
174
- });
175
- const addedTransactions = (localData.statementTransactions?.added ?? []).map((transaction, index) => mapLocalTransactionToFormRow(transaction, `added-${index}`));
176
- return [...persistedTransactions, ...addedTransactions];
177
- };
178
67
  export const mergeStatementParseDeletedTransactionIds = (originalTransactions, statementPeriod, currentTransactionIds) => {
179
68
  const dateFilteredDeletedIds = getDateFilteredDeletedTransactionIds(originalTransactions, statementPeriod);
180
69
  const dateFilteredDeletedIdSet = new Set(dateFilteredDeletedIds);
@@ -185,116 +74,3 @@ export const mergeStatementParseDeletedTransactionIds = (originalTransactions, s
185
74
  .map((transaction) => transaction.statementTransactionId);
186
75
  return [...new Set([...userDeletedIds, ...dateFilteredDeletedIds])];
187
76
  };
188
- const resolveStatementMetaDates = (parsedStatementMeta, localMeta) => ({
189
- statementStartDate: localMeta?.statementStartDate != null && localMeta.statementStartDate !== ''
190
- ? localMeta.statementStartDate
191
- : (parsedStatementMeta?.statementStartDate ?? ''),
192
- statementEndDate: localMeta?.statementEndDate != null && localMeta.statementEndDate !== ''
193
- ? localMeta.statementEndDate
194
- : (parsedStatementMeta?.statementEndDate ?? ''),
195
- });
196
- export const getStatementParseFormView = ({ accountType, parsedStatementMeta, originalTransactions, statementUpdateLocalData, }) => {
197
- const transactions = statementUpdateLocalData != null
198
- ? buildStatementParseFormTransactions(originalTransactions, statementUpdateLocalData)
199
- : originalTransactions.map(mapParsedTransactionToFormRow);
200
- const localMeta = statementUpdateLocalData?.statementMeta;
201
- const { statementStartDate, statementEndDate } = resolveStatementMetaDates(parsedStatementMeta, localMeta);
202
- const { totalDeposits, totalPayments } = computeStatementTransactionTotals(filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate));
203
- const openingBalance = localMeta?.openingBalance ?? parsedStatementMeta?.openingBalance ?? 0;
204
- const computedClosingBalance = computeStatementClosingBalance(openingBalance, totalDeposits, totalPayments, accountType);
205
- return {
206
- statementStartDate,
207
- statementEndDate,
208
- openingBalance,
209
- closingBalance: localMeta?.closingBalance ?? computedClosingBalance,
210
- totalDeposits: localMeta?.totalDeposits ?? totalDeposits,
211
- totalPayments: localMeta?.totalPayments ?? totalPayments,
212
- transactions: filterFormTransactionsInPeriod(transactions, statementStartDate, statementEndDate),
213
- };
214
- };
215
- export const toStatementUpdateLocalDataFromFormView = ({ accountType, formView, parsedStatementMeta, originalTransactions, changedField, }) => {
216
- const balanceFields = resolveStatementParseBalanceFields(formView, changedField, accountType);
217
- const currentTransactionIds = new Set(formView.transactions
218
- .map((transaction) => transaction.statementTransactionId)
219
- .filter((id) => id != null && id !== ''));
220
- const added = [];
221
- const updated = [];
222
- formView.transactions.forEach((transaction) => {
223
- const transactionDate = toApiDateString(transaction.transactionDate);
224
- if (transaction.statementTransactionId == null) {
225
- if (transaction.transactionDirection != null) {
226
- added.push({
227
- amount: transaction.amount,
228
- transactionDate,
229
- transactionDirection: transaction.transactionDirection,
230
- transactionMemo: transaction.transactionMemo,
231
- });
232
- }
233
- return;
234
- }
235
- const original = originalTransactions.find((candidate) => candidate.statementTransactionId === transaction.statementTransactionId);
236
- if (original != null &&
237
- (original.amount !== transaction.amount ||
238
- toApiDateString(original.transactionDate) !== transactionDate ||
239
- original.transactionMemo !== transaction.transactionMemo)) {
240
- updated.push({
241
- amount: transaction.amount,
242
- transactionDate,
243
- transactionDirection: transaction.transactionDirection,
244
- transactionMemo: transaction.transactionMemo,
245
- statementTransactionId: transaction.statementTransactionId,
246
- });
247
- }
248
- });
249
- const statementPeriod = {
250
- statementStartDate: toApiDateString(formView.statementStartDate),
251
- statementEndDate: toApiDateString(formView.statementEndDate),
252
- };
253
- const deletedIds = mergeStatementParseDeletedTransactionIds(originalTransactions, statementPeriod, currentTransactionIds);
254
- const deletedIdSet = new Set(deletedIds);
255
- const inPeriodAdded = filterFormTransactionsInPeriod(added, statementPeriod.statementStartDate, statementPeriod.statementEndDate);
256
- const inPeriodUpdated = updated.filter((transaction) => transaction.statementTransactionId != null &&
257
- !deletedIdSet.has(transaction.statementTransactionId));
258
- return {
259
- statementMeta: {
260
- closingBalance: balanceFields.closingBalance,
261
- openingBalance: balanceFields.openingBalance,
262
- statementDataStatus: parsedStatementMeta?.statementDataStatus ?? {
263
- code: '',
264
- label: '',
265
- },
266
- statementEndDate: statementPeriod.statementEndDate,
267
- statementStartDate: statementPeriod.statementStartDate,
268
- statementStatus: parsedStatementMeta?.statementStatus ?? {
269
- code: '',
270
- label: '',
271
- },
272
- statementUploadId: parsedStatementMeta?.statementUploadId ?? '',
273
- totalDeposits: balanceFields.totalDeposits,
274
- totalPayments: balanceFields.totalPayments,
275
- },
276
- statementTransactions: {
277
- added: inPeriodAdded,
278
- deletedIds,
279
- updated: inPeriodUpdated,
280
- },
281
- };
282
- };
283
- export const applyStatementParseFormChange = ({ accountType, formView, changedField, parsedStatementMeta, originalTransactions, }) => {
284
- const balanceFields = resolveStatementParseBalanceFields(formView, changedField, accountType);
285
- const shouldRecalculate = shouldRecalculateStatementParseBalances(changedField);
286
- const mergedFormView = shouldRecalculate
287
- ? { ...formView, ...balanceFields }
288
- : formView;
289
- return {
290
- didRecalculateBalances: shouldRecalculate,
291
- formView: mergedFormView,
292
- localData: toStatementUpdateLocalDataFromFormView({
293
- accountType,
294
- formView: mergedFormView,
295
- parsedStatementMeta,
296
- originalTransactions,
297
- changedField,
298
- }),
299
- };
300
- };
@@ -11,7 +11,7 @@ import { getCompanyAndIdentityDetails, } from '../../spendManagement/commonSetup
11
11
  import { ALL_ONBOARDING_STEPS, ALL_ZENI_USER_BOOKKEEPING_ONBOARDING_STEPS, ALL_ZENI_USER_ONBOARDING_STEPS, REQUIRED_ONBOARDING_STEPS, ZENI_USER_REQUIRED_ONBOARDING_STEPS, emptyAiAgentsActivationSubview, toOnboardingStepType, } from './onboardingCustomerViewState';
12
12
  export function getOnboardingCustomerView(state, companyId) {
13
13
  const { fileState, paymentAccountState, onboardingCustomerViewState, userState, userRoleState, subscriptionPaymentAccountState, companyConfigState, cardPaymentViewState, countryListState, addressViewState, } = state;
14
- const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, parsingDocumentFileIds, updateStatus, saveStatus, currentStep, currentSubStep, uiState, fetchState, error, } = onboardingCustomerViewState;
14
+ const { companyDetails, companyOfficerUpdateStatus, primaryContactDetails, subscriptionPaymentAccountIds, paymentAccountDetails, plaidConnectionDetails, parsingDocumentFileIds, updateStatus, saveStatus, aiFinanceTeamAcknowledgementStatus, currentStep, currentSubStep, uiState, fetchState, error, } = onboardingCustomerViewState;
15
15
  const { paymentAccountIds } = paymentAccountDetails;
16
16
  let subscriptionPaymentAccount;
17
17
  let paymentAccount;
@@ -148,6 +148,7 @@ export function getOnboardingCustomerView(state, companyId) {
148
148
  fetchStatus,
149
149
  saveStatus,
150
150
  updateStatus,
151
+ aiFinanceTeamAcknowledgementStatus,
151
152
  qboConnected: onboardingInfo?.qboLinked.completed ?? false,
152
153
  isInterimEmailSent: onboardingInfo?.isInterimEmailSent ?? false,
153
154
  };
@@ -10,7 +10,7 @@ import { getActualTransactionID } from '../transactionDetail/transactionDetailSt
10
10
  import { getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT, getRecommendationFromRecommendationPayload, } from './recommendationHelper';
11
11
  import { fetchEntityRecommendationsByTransactionId, updateRecommendationForEntity, updateRecommendationForEntityFailure, } from './recommendationReducer';
12
12
  export const fetchEntityRecommendationsByTransactionIdEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchEntityRecommendationsByTransactionId.match), switchMap((action) => {
13
- const { entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = action.payload;
13
+ const { entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow, isFetchCOT, } = action.payload;
14
14
  const { expenseAutomationTransactionsViewState: { selectedTransactionCategorizationTab, }, } = state$.value;
15
15
  const query = {
16
16
  amount,
@@ -52,7 +52,7 @@ export const fetchEntityRecommendationsByTransactionIdEpic = (actions$, state$,
52
52
  if (recommendationWithCOTByLineId != null) {
53
53
  const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
54
54
  if (isTransactionCategorizationFlow === true) {
55
- actions.push(setEntityRecommendationForLineIdsForCategorization(selectedTransactionCategorizationTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
55
+ actions.push(setEntityRecommendationForLineIdsForCategorization(selectedTransactionCategorizationTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, getIsAccountingClassesEnabled(state$.value)));
56
56
  }
57
57
  else {
58
58
  actions.push(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense));
@@ -37,7 +37,7 @@ const toGroupKey = (flowType, transactionId, lineIds) => `${flowType}${SEPARATOR
37
37
  export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchEntityRecommendationsForLineUpdate.match), groupBy((action) => toGroupKey(action.payload.flowType, action.payload.transactionDetails.transactionId.id, action.payload.transactionDetails.lineIds), undefined, (group$) => group$.pipe(debounce(() => timer(GROUP_INACTIVITY_TIMEOUT_MS)))), mergeMap((group$) => group$.pipe(switchMap((action) => {
38
38
  const payload = action.payload;
39
39
  const { transactionId, transaction, lineIds } = payload.transactionDetails;
40
- const { entity, amount, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = payload;
40
+ const { entity, amount, isFetchCOT, } = payload;
41
41
  // The vendor "Update all lines" popup on the detail page watches
42
42
  // its own transaction-level fetch status, separate from the
43
43
  // per-line statuses below — surface completion/failure there too
@@ -84,7 +84,7 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
84
84
  : getTransactionWithCOT(transaction);
85
85
  const uncategorizedIncomeExpense = getUncategorizedAccounts(state$.value.accountState, state$.value.accountListState, 'accountList');
86
86
  if (payload.flowType === 'categorization') {
87
- return of(setEntityRecommendationForLineIdsForCategorization(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
87
+ return of(setEntityRecommendationForLineIdsForCategorization(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, getIsAccountingClassesEnabled(state$.value)));
88
88
  }
89
89
  return emitWithBulkStatus(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense), isBulkDetailFetch
90
90
  ? updateVendorBulkRecommendationsFetchStatus(transactionId, 'Completed')
@@ -19,7 +19,7 @@ const recommendation = createSlice({
19
19
  };
20
20
  }
21
21
  },
22
- prepare(entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow = false, isFetchCOT = false, isUncategorizedExpenseCategoryEnabled) {
22
+ prepare(entity, amount, transactionDetails, isBulkFetch, isTransactionCategorizationFlow = false, isFetchCOT = false) {
23
23
  return {
24
24
  payload: {
25
25
  entity,
@@ -28,7 +28,6 @@ const recommendation = createSlice({
28
28
  isBulkFetch,
29
29
  isTransactionCategorizationFlow,
30
30
  isFetchCOT,
31
- isUncategorizedExpenseCategoryEnabled,
32
31
  },
33
32
  };
34
33
  },
@@ -134,9 +133,25 @@ const recommendation = createSlice({
134
133
  clearRecommendation(draft) {
135
134
  Object.assign(draft, initialState);
136
135
  },
136
+ // Fire-and-forget human feedback on a recommendation (accept, ranked
137
+ // override or outside override). Handled by submitRecommendationFeedbackEpic
138
+ // which POSTs to the accounting recommendation-feedback endpoint. No state
139
+ // mutation: the categorization UX must not depend on the feedback round-trip.
140
+ submitRecommendationFeedback: {
141
+ reducer(
142
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
143
+ _draft,
144
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
145
+ _action) {
146
+ // do nothing
147
+ },
148
+ prepare(args) {
149
+ return { payload: args };
150
+ },
151
+ },
137
152
  },
138
153
  });
139
- export const { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, clearRecommendation, } = recommendation.actions;
154
+ export const { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, clearRecommendation, submitRecommendationFeedback, } = recommendation.actions;
140
155
  export default recommendation.reducer;
141
156
  const doUpdateRecommendationForEntity = (draft, entityId, entityType, payload) => {
142
157
  const key = getEntityRecommendationKey(entityType, entityId);
@@ -0,0 +1,51 @@
1
+ import { EMPTY } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { isSuccessStatus } from '../../responsePayload';
4
+ import { submitRecommendationFeedback } from './recommendationReducer';
5
+ const toRequestBody = (payload) => ({
6
+ line_id: payload.lineId ?? null,
7
+ dimension: payload.dimension,
8
+ recommendation_set_id: payload.recommendationSetId ?? null,
9
+ top_pick_source: payload.topPickSource ?? null,
10
+ shown_recommendations: (payload.shownRecommendations ?? []).map((recommendation) => ({
11
+ source: recommendation.source,
12
+ rank: recommendation.rank,
13
+ value: {
14
+ name: recommendation.value.name,
15
+ id: recommendation.value.id ?? null,
16
+ integration_id: recommendation.value.integrationId ?? null,
17
+ },
18
+ confidence: recommendation.confidence ?? null,
19
+ reasoning: recommendation.reasoning ?? null,
20
+ cot: recommendation.cot ?? [],
21
+ })),
22
+ selected: {
23
+ name: payload.selected.name,
24
+ id: payload.selected.id ?? null,
25
+ integration_id: payload.selected.integrationId ?? null,
26
+ is_new_entity: payload.selected.isNewEntity ?? false,
27
+ },
28
+ matched_source: payload.matchedSource ?? null,
29
+ matched_rank: payload.matchedRank ?? null,
30
+ outcome: payload.outcome,
31
+ reason_text: payload.reasonText ?? null,
32
+ skipped: payload.skipped ?? false,
33
+ features: payload.features ?? null,
34
+ });
35
+ // Fire-and-forget: the epic never re-emits an action. Feedback delivery is a
36
+ // side-effect that must not disrupt the categorization UX, so both the
37
+ // success and error paths complete silently (errors are logged for debugging).
38
+ export const submitRecommendationFeedbackEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(submitRecommendationFeedback.match), mergeMap((action) => {
39
+ const { transactionId } = action.payload;
40
+ return zeniAPI
41
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${transactionId}/recommendation-feedback`, toRequestBody(action.payload))
42
+ .pipe(mergeMap((response) => {
43
+ if (!isSuccessStatus(response)) {
44
+ console.error('submitRecommendationFeedbackEpic: recommendation feedback was not recorded', response.status);
45
+ }
46
+ return EMPTY;
47
+ }), catchError((error) => {
48
+ console.error('submitRecommendationFeedbackEpic: failed to submit recommendation feedback', error);
49
+ return EMPTY;
50
+ }));
51
+ }));
@@ -7,7 +7,7 @@ import { saveTransactionDetail, updateTransactionDetail, } from '../transactionD
7
7
  import { getTransactionDetailKey } from '../transactionDetailState';
8
8
  import { toTransactionUpdatesFromTransactionDetailLocalData } from './saveTransactionHelper';
9
9
  export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(filter(saveTransactionDetail.match), mergeMap((action) => {
10
- const { transactionId, cotTransactionTracking, isExpenseAutomationEnabled, isUncategorizedExpenseCategoryEnabled, } = action.payload;
10
+ const { transactionId, cotTransactionTracking, isExpenseAutomationEnabled, } = action.payload;
11
11
  const fetchActions = [];
12
12
  const transactionDetailState = state$.value.transactionDetailState;
13
13
  const transactionState = state$.value.transactionState;
@@ -18,7 +18,7 @@ export const saveTransactionDetailEpic = (actions$, state$) => actions$.pipe(fil
18
18
  if (detail != null && transaction != null) {
19
19
  const localData = detail.transactionDetailLocalData;
20
20
  const transactionSaveUpdates = toTransactionUpdatesFromTransactionDetailLocalData(localData, transaction, isExpenseAutomationEnabled, isAccountingProjectsEnabled);
21
- fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled));
21
+ fetchActions.push(updateTransactionDetail(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking));
22
22
  return from(fetchActions);
23
23
  }
24
24
  return from(fetchActions);
@@ -29,7 +29,7 @@ import { getTransactionDetailKey, } from '../transactionDetailState';
29
29
  export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateTransactionDetail.match), mergeMap((action) => {
30
30
  const { transactionState, vendorState, transactionDetailState } = state$.value;
31
31
  const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state$.value);
32
- const { cotTransactionTracking, transactionId, transactionSaveUpdates, isUncategorizedExpenseCategoryEnabled, } = action.payload;
32
+ const { cotTransactionTracking, transactionId, transactionSaveUpdates, } = action.payload;
33
33
  return zeniAPI
34
34
  .putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/transactions/${action.payload.transactionId.id}/categorize`, preparePayload(transactionState, vendorState, transactionDetailState, transactionId, transactionSaveUpdates, cotTransactionTracking, isAccountingProjectsEnabled))
35
35
  .pipe(mergeMap((response) => {
@@ -82,7 +82,7 @@ export const updateTransactionDetailEpic = (actions$, state$, zeniAPI) => action
82
82
  actions.push(updateTransactions([response.data.transaction], (value) => value.transaction_id, 'merge'));
83
83
  const transactionWithCOT = getTransactionWithCOT(transaction);
84
84
  const pendingReviewLineIds = getPendingReviewLineIdsFromTransaction(transactionWithCOT);
85
- actions.push(syncTransactionCategorizationFromDetailSave(transactionIdResp, transactionWithCOT, pendingReviewLineIds, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled));
85
+ actions.push(syncTransactionCategorizationFromDetailSave(transactionIdResp, transactionWithCOT, pendingReviewLineIds));
86
86
  return from(actions);
87
87
  }
88
88
  else if (isActionNotAllowed(response)) {
@@ -105,14 +105,13 @@ const transactionDetail = createSlice({
105
105
  };
106
106
  }
107
107
  },
108
- prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking, isUncategorizedExpenseCategoryEnabled) {
108
+ prepare(transactionId, transactionSaveUpdates, isExpenseAutomationEnabled, cotTransactionTracking) {
109
109
  return {
110
110
  payload: {
111
111
  transactionId,
112
112
  transactionSaveUpdates,
113
113
  isExpenseAutomationEnabled,
114
114
  cotTransactionTracking,
115
- isUncategorizedExpenseCategoryEnabled,
116
115
  },
117
116
  };
118
117
  },
package/lib/index.d.ts CHANGED
@@ -292,7 +292,6 @@ import { ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSel
292
292
  import { getExpenseAutomationFluxAnalysisView } from './view/expenseAutomationView/selectors/fluxAnalysisViewSelector';
293
293
  import { JEScheduledTransactionWithFailedEntries } from './view/expenseAutomationView/selectors/jeSchedulesViewSelector';
294
294
  import { getExpenseAutomationReconciliationView, getReparseStatementStatusByAccountId, isAccountReconReport } from './view/expenseAutomationView/selectors/reconciliationViewSelector';
295
- import { applyStatementParseFormChange, areStatementParseBalancesConsistent, getStatementParseFormView } from './view/expenseAutomationView/selectors/statementParseViewSelector';
296
295
  import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
297
296
  import { TRANSACTION_FILTER_CATEGORIES, TransactionFilterAmountMatchingOperator, TransactionFilterCategory, TransactionFilterCategoryDropdownOption, TransactionFilterCategoryField, TransactionFilterEntityType, TransactionFilters, applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
298
297
  import { CompletedSubTab, DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab } from './view/expenseAutomationView/types/completedSubTab';
@@ -300,7 +299,7 @@ import { FluxAnalysisActionType, FluxAnalysisReviewStatus, FluxAnalysisSortKey,
300
299
  import { AccountSettingsLocalData, JEScheduleMainTab as ExpenseAutomationJEScheduleMainTab, JEScheduleSortKey as ExpenseAutomationJEScheduleSortKey, JESchedulesViewUIState as ExpenseAutomationJESchedulesViewUIState, JEScheduleLocalData, toJEScheduleMainTab as toExpenseAutomationJEScheduleMainTab, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey } from './view/expenseAutomationView/types/jeSchedulesViewState';
301
300
  import { BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, MatchCandidate, MatchSource, MissingReceiptsTab, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab } from './view/expenseAutomationView/types/missingReceiptsViewState';
302
301
  import { MissingReceiptsSortKey as ExpenseAutomationMissingReceiptsSortKey, MissingReceiptsViewState as ExpenseAutomationMissingReceiptsViewState, MissingReceiptsViewUIState as ExpenseAutomationMissingReceiptsViewUIState, toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey } from './view/expenseAutomationView/types/missingReceiptsViewState';
303
- import { AccountReconciliationLocalData, ExcludeAccountFromReconciliationPayload, ReconciliationViewTabType as ExpenseAutomationReconciliationViewTab, ParsedStatementData, ReconReconcileSortKey, ReconReviewSortKey, ReconciliationReconcileTabLocalData, ReconciliationReviewTabLocalData, SaveReconcileDetailActionPayload as SaveExpenseAutomationReconciliationActionType, StatementDateConflict, StatementMeta, StatementParseFormView, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, StatementUpdateLocalData, toReconciliationTabsType } from './view/expenseAutomationView/types/reconciliationViewState';
302
+ import { AccountReconciliationLocalData, ExcludeAccountFromReconciliationPayload, ReconciliationViewTabType as ExpenseAutomationReconciliationViewTab, ParsedStatementData, ReconReconcileSortKey, ReconReviewSortKey, ReconciliationReconcileTabLocalData, ReconciliationReviewTabLocalData, SaveReconcileDetailActionPayload as SaveExpenseAutomationReconciliationActionType, StatementDateConflict, StatementMeta, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, StatementUpdateLocalData, toReconciliationTabsType } from './view/expenseAutomationView/types/reconciliationViewState';
304
303
  import { TransactionsTab as ExpenseAutomationTransactionsTab, TransactionsViewState as ExpenseAutomationTransactionsViewState, TransactionsViewUIState as ExpenseAutomationTransactionsViewUIState, SupportedTransactionCategorization, TransactionCategorizationLineItemData, TransactionReviewLocalData, TransactionsSortKey, TransactionsTab, toTransactionsTabKey as toExpenseAutomationTransactionsTabKey, toTransactionsSortKey } from './view/expenseAutomationView/types/transactionsViewState';
305
304
  import { clearFeatureNotificationView, fetchRegisteredInterests, notifyMeForFeature } from './view/featureNotificationView/featureNotificationViewReducer';
306
305
  import { getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered } from './view/featureNotificationView/featureNotificationViewSelector';
@@ -379,7 +378,7 @@ import { ProfitAndLossProjectViewReport } from './view/profitAndLossProjectView/
379
378
  import { ProfitAndLossProjectViewUIState } from './view/profitAndLossProjectView/profitAndLossProjectViewState';
380
379
  import { fetchProjectList } from './view/projectList/projectListReducer';
381
380
  import { ProjectListSelectorView, getProjectList } from './view/projectList/projectListSelector';
382
- import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName } from './view/recommendation/recommendationReducer';
381
+ import { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback } from './view/recommendation/recommendationReducer';
383
382
  import { DEFAULT_REFERRER_AMOUNT, clearReferrals, fetchReferrals, fetchRewardsPlan, resendReferralInvite, saveReferralFormDataInLocalStore, sendReferralInvite, updateReferViewed, updateReferralListSortUiState } from './view/referralView/referralReducer';
384
383
  import { ReferralListSelectorView, RewardsPlanCardReport, getInviteFormView, getReferralListView, getRewardsPlanCard } from './view/referralView/referralSelector';
385
384
  import { AmountStatusTypes, InviteCompanyLocalData, ReferralAmountStatus, ReferralInvitation, ReferralListViewSortKey, ReferralStatus, ReferralViewState, ReferralViewUIState, RewardsPlanData, StatusTypes, toReferralListViewSortKeyType } from './view/referralView/referralState';
@@ -675,7 +674,7 @@ export { TransactionsOrder, COABalancesSliceOrder, EntityOrder, Section, Section
675
674
  export { ClassesViewSelectorReportV2 };
676
675
  export { BalancesTimeseries, TrendTimeseries, BalanceKind };
677
676
  export { fetchMonthEndCloseChecks, fetchMonthClosePerformanceTrend, MonthClosePerformanceTrend, MonthEndCloseCheck, getMonthEndCloseChecksViewByTenantId, MonthEndCloseChecksView, MonthEndCloseCheckFrequency, MonthCloseCheckMetrics, MonthCloseCheckProgressJson, ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, MonthEndAuditSummary, };
678
- export { ExpenseAutomationViewSelector, ExpenseAutomationStepDetails, ExpenseAutomationViewType, ExpenseAutomationMissingReceiptsViewSelector, BulkUploadSelectorData, ExpenseAutomationFluxAnalysisViewSelector, FluxAnalysisVendorView, FluxAnalysisViewSectionReport, FluxVendorAccountsAndClassesView, ExpenseAutomationMissingReceiptsViewUIState, ExpenseAutomationMissingReceiptsViewState, ExpenseAutomationViewState, ExpenseAutomationTransactionsTab, ExpenseAutomationMissingReceiptsSortKey, BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, isUnmatchedTabFileStatus, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, CompletedTransactionsSelectorData, DEFAULT_COMPLETED_SUB_TAB, MatchCandidate, MatchSource, MissingReceiptsTab, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ResolvedBatchFile, ResolvedBatchDetails, ResolvedCandidate, ExpenseAutomationJEScheduleMainTab, ExpenseAutomationJEScheduleSortKey, ExpenseAutomationJESchedulesViewUIState, toExpenseAutomationJEScheduleMainTab, toExpenseAutomationJEScheduleSortKey, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, fetchExpenseAutomationMissingReceipts, bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, FluxAnalysisOperatingExpenseView, FluxAnalysisSectionType, getExpenseAutomationFluxAnalysisView, FluxAnalysisSortKey, FluxAnalysisActionType, FluxBalancesByMonth, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, ReconReconcileSortKey, ReconciliationReconcileTabLocalData, FluxAnalysisReviewStatus, updateFluxAnalysisViewUIState, FluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, SaveExpenseAutomationReconciliationActionType, ExcludeAccountFromReconciliationPayload, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, ExpenseAutomationReconciliationViewSelector, getExpenseAutomationReconciliationView, getReparseStatementStatusByAccountId, applyStatementParseFormChange, areStatementParseBalancesConsistent, getStatementParseFormView, AccountReconciliationBySection, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, UploadStatementDocumentAIResponse, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, AccountReconciliationByAccount, AccountReconciliationEntity, getAccountReconByAccountIdAndSelectedPeriod, ExpenseAutomationReconciliationViewTab, toReconciliationTabsType, isAccountReconReport, ReconReviewSortKey, AccountReconSectionID, ReconciliationReviewTabLocalData, TransactionsToReview, RecommendedActionCodeType, ReconciliationStatusCodeType, BalanceDataStatusCodeType, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, BankStatusCodeType, ReconciliationAccountSourceType, toReconciliationAccountSource, StatementStatusCodeType, AccountReconciliationLocalData, StatementDataStatusCodeType, deleteAccountStatement, uploadAccountStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, UploadStatementDocumentAIPayload, updateStatementUploadChosen, submitStatementUpdate, clearStatementDateConflict, StatementDateConflict, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, ParsedStatementData, StatementUpdateLocalData, StatementParseFormView, StatementMeta, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, };
677
+ export { ExpenseAutomationViewSelector, ExpenseAutomationStepDetails, ExpenseAutomationViewType, ExpenseAutomationMissingReceiptsViewSelector, BulkUploadSelectorData, ExpenseAutomationFluxAnalysisViewSelector, FluxAnalysisVendorView, FluxAnalysisViewSectionReport, FluxVendorAccountsAndClassesView, ExpenseAutomationMissingReceiptsViewUIState, ExpenseAutomationMissingReceiptsViewState, ExpenseAutomationViewState, ExpenseAutomationTransactionsTab, ExpenseAutomationMissingReceiptsSortKey, BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, isUnmatchedTabFileStatus, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, CompletedSubTab, CompletedTransactionsSelectorData, DEFAULT_COMPLETED_SUB_TAB, MatchCandidate, MatchSource, MissingReceiptsTab, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ResolvedBatchFile, ResolvedBatchDetails, ResolvedCandidate, ExpenseAutomationJEScheduleMainTab, ExpenseAutomationJEScheduleSortKey, ExpenseAutomationJESchedulesViewUIState, toExpenseAutomationJEScheduleMainTab, toExpenseAutomationJEScheduleSortKey, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, fetchExpenseAutomationMissingReceipts, bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, FluxAnalysisOperatingExpenseView, FluxAnalysisSectionType, getExpenseAutomationFluxAnalysisView, FluxAnalysisSortKey, FluxAnalysisActionType, FluxBalancesByMonth, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, ReconReconcileSortKey, ReconciliationReconcileTabLocalData, FluxAnalysisReviewStatus, updateFluxAnalysisViewUIState, FluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, SaveExpenseAutomationReconciliationActionType, ExcludeAccountFromReconciliationPayload, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, ExpenseAutomationReconciliationViewSelector, getExpenseAutomationReconciliationView, getReparseStatementStatusByAccountId, AccountReconciliationBySection, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, UploadStatementDocumentAIResponse, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, AccountReconciliationByAccount, AccountReconciliationEntity, getAccountReconByAccountIdAndSelectedPeriod, ExpenseAutomationReconciliationViewTab, toReconciliationTabsType, isAccountReconReport, ReconReviewSortKey, AccountReconSectionID, ReconciliationReviewTabLocalData, TransactionsToReview, RecommendedActionCodeType, ReconciliationStatusCodeType, BalanceDataStatusCodeType, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, BankStatusCodeType, ReconciliationAccountSourceType, toReconciliationAccountSource, StatementStatusCodeType, AccountReconciliationLocalData, StatementDataStatusCodeType, deleteAccountStatement, uploadAccountStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, UploadStatementDocumentAIPayload, updateStatementUploadChosen, submitStatementUpdate, clearStatementDateConflict, StatementDateConflict, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, ParsedStatementData, StatementUpdateLocalData, StatementMeta, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, };
679
678
  export { JEScheduleLocalData };
680
679
  export { ExpenseAutomationJESchedulesViewSelector, JEAccountSettingsView, JEScheduledTransactionWithFailedEntries, };
681
680
  export { fetchTransactionCategorization, fetchTransactionCategorizationView, updateTransactionCategorizationUIState, updateTransactionFilters, updateSelectedCheckboxTransactionIds, markCategoryClassRecommendationsFailureForCategorization, setEntityRecommendationForLineIdsForCategorization, initializeTransactionCategorizationViewLocalData, setAllItemsToCategoryClassInLocalDataForCategorization, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, createTransferEntry, createTransferEntryFailure, createTransferEntryReplacedTransaction, createTransferEntrySuccess, resetCreateTransferEntryStatus, clearTransferEntryRouteReplacement, fetchAccountsForTransferFlow, removeTransactionFromAllTabs, clearExpenseAutomationTransactionsView, TransactionsSortKey, toTransactionsSortKey, TransactionsTab, TransactionCategorizationLineItemData, TransactionReviewLocalData, SupportedTransactionCategorization, ExpenseAutomationTransactionsViewState, ExpenseAutomationTransactionsViewUIState, ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSelectorView, };
@@ -854,7 +853,7 @@ export { Filing1099TinType };
854
853
  export { BillPayCardReport };
855
854
  export { ReimbursementCardReport };
856
855
  export { VendorListViewSortKey, VendorViewUIState, VendorListSelectorView, VendorListQuery, getVendorList, VendorListView, updateSortUiState, updatePageToken, updateYTDSelectionUIState, VendorListViewYTDSpendSortKey, isColumnYTDSpend, isVendorsTabVisible, VendorViewType, VendorReportIDType, toVendorReportIDType, VendorFiling1099ListSelectorView, getVendorFiling1099List, VendorFiling1099ListViewSortKey, VendorFiling1099ViewUIState, VendorFiling1099DownloadData, fetchVendorsFiling1099Download, Type1099Download, VendorFiling1099DownloadDataForType, };
857
- export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, };
856
+ export { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityId, fetchRecommendationByEntityName, submitRecommendationFeedback, };
858
857
  export type { FetchEntityRecommendationsForLineUpdatePayload, RecommendationLineUpdateFlowType, } from './view/recommendation/recommendationReducer';
859
858
  export { fetchOwnerList };
860
859
  export { ZeniAccountsConfigSelectorView, getZeniAccountsConfigDetail, ZeniAccountListSelectorView, getZeniAccountList, fetchZeniAccountList, fetchAccountList, DepositAccount, createCheckingAccount, fetchPaymentAccountList, unlinkPaymentAccount, getDepositAccountDetail, DepositAccountDetailSelectorView, DepositAccountListSelectorView, getAllDepositAccounts, getDepositAccountDetailForPDF, DepositAccountDetailForPDF, fetchDepositAccount, fetchZeniAccountsConfig, AccountHistoryWithBalances, TransferDetailLocalData, ReviewTransferDetail, updateTransferMoneyLocalData, updateTransferToLocalData, updateDepositToLocalData, transferMoney, getTransferDetail, TransferDetailSelectorView, clearTransferDetail, clearReviewTransferDetail, fetchReviewTransferDetail, fetchDepositAccountDetail, DepositAccountTransaction, DepositAccountWithAutoTransferRules, DepositTransactionStatusCode, DepositTransactionStatus, CheckDepositLocalData, depositCheck, updateCheckDepositLocalData, clearCheckDeposit, CheckDepositSelectorView, getCheckDepositDetail, updateDepositAccount, fetchDepositAccountHistorySuccess, fetchDepositAccountHistoryFailure, DepositAccountUpdateType, ZeniAccountSummaryWithBalance, fetchZeniAccStatementPage, getZeniAccStatements, ZeniAccStatementsSelectorView, ZeniAccountPaymentMethod, };