@zeniai/client-epic-state 5.2.34 → 5.2.35-beta1MM

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 (97) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +25 -0
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +45 -0
  3. package/lib/entity/actualMatching/actualMatchingReducer.d.ts +8 -0
  4. package/lib/entity/actualMatching/actualMatchingReducer.js +33 -0
  5. package/lib/entity/actualMatching/actualMatchingSelector.d.ts +3 -0
  6. package/lib/entity/actualMatching/actualMatchingSelector.js +6 -0
  7. package/lib/entity/actualMatching/actualMatchingState.d.ts +22 -0
  8. package/lib/entity/actualMatching/actualMatchingState.js +2 -0
  9. package/lib/entity/actualMatching/actualMatchingTypes.d.ts +1 -0
  10. package/lib/entity/actualMatching/actualMatchingTypes.js +2 -0
  11. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +29 -0
  12. package/lib/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  13. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +31 -0
  14. package/lib/epic.d.ts +8 -1
  15. package/lib/epic.js +14 -0
  16. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +42 -0
  17. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
  18. package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
  19. package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
  20. package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
  21. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  22. package/lib/esm/epic.js +14 -0
  23. package/lib/esm/index.js +7 -3
  24. package/lib/esm/reducer.js +6 -0
  25. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +44 -0
  26. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
  27. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
  28. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +51 -0
  29. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
  30. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +77 -0
  31. package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +51 -0
  32. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  33. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  34. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  35. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  36. package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +23 -7
  37. package/lib/esm/view/expenseAutomationView/expenseAutomationViewState.js +4 -2
  38. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
  39. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +371 -0
  40. package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
  41. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +287 -0
  42. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +4 -0
  43. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +32 -0
  44. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -1
  45. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  46. package/lib/index.d.ts +14 -6
  47. package/lib/index.js +79 -48
  48. package/lib/reducer.d.ts +2 -0
  49. package/lib/reducer.js +6 -0
  50. package/lib/rootStateTypes.d.ts +4 -0
  51. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
  52. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +48 -0
  53. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  54. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
  55. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
  56. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
  57. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
  58. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +55 -0
  59. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +9 -0
  60. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +52 -0
  61. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
  62. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +81 -0
  63. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
  64. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +55 -0
  65. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
  66. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  67. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
  68. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  69. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  70. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
  71. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  72. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +23 -7
  73. package/lib/view/expenseAutomationView/expenseAutomationViewState.d.ts +2 -1
  74. package/lib/view/expenseAutomationView/expenseAutomationViewState.js +6 -3
  75. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
  76. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
  77. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +76 -0
  78. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +375 -0
  79. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +4 -4
  80. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +83 -0
  81. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
  82. package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +11 -0
  83. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +31 -0
  84. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +303 -0
  85. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +4 -0
  86. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +99 -0
  87. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
  88. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  89. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -1
  90. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.d.ts +1 -11
  91. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  92. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +1 -2
  93. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +1 -2
  94. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +15 -1
  95. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
  96. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +1 -1
  97. package/package.json +1 -1
@@ -4,6 +4,7 @@ import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/ti
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
5
  import { fetchCompanyMonthEndReportTemplates, fetchCompanyMonthEndReportView, } from '../../../companyMonthEndReportView/companyMonthEndReportViewReducer';
6
6
  import { refreshExpenseAutomationCurrentTab } from '../../expenseAutomationViewReducer';
7
+ import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
7
8
  import { fetchFluxAnalysisView } from '../../reducers/fluxAnalysisViewReducer';
8
9
  import { fetchJeSchedulesPage } from '../../reducers/jeSchedulesViewReducer';
9
10
  import { fetchMissingReceipts } from '../../reducers/missingReceiptsViewReducer';
@@ -38,10 +39,17 @@ export const refreshExpenseAutomationCurrentTabEpic = (actions$, state$) => acti
38
39
  return from([
39
40
  fetchFluxAnalysisView(selectedPeriod, true, true, null),
40
41
  ]);
41
- case 'je_schedules':
42
+ case 'je_schedules': {
43
+ const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
44
+ if (selectedPageTab === 'actual_matching') {
45
+ return from([
46
+ fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, true),
47
+ ]);
48
+ }
42
49
  return from([
43
50
  fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, true),
44
51
  ]);
52
+ }
45
53
  case 'month_end_insights':
46
54
  return from([
47
55
  fetchCompanyMonthEndReportView(true, companyId, currentTenant.tenantId, period.end, true),
@@ -14,7 +14,9 @@ export const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pi
14
14
  const state = state$.value;
15
15
  const { period } = action.payload;
16
16
  const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
17
- const otherPageTab = ALL_JE_PAGE_TABS.find((pageTab) => pageTab !== selectedPageTab);
17
+ // Actual Matching has its own CES slice and API; warming it with fetchJeSchedules
18
+ // would prefetch the wrong endpoint. Only Review <-> Existing share that fetch.
19
+ const otherPageTab = ALL_JE_PAGE_TABS.find((pageTab) => pageTab !== selectedPageTab && pageTab !== 'actual_matching');
18
20
  if (otherPageTab == null) {
19
21
  return EMPTY;
20
22
  }
@@ -2,6 +2,7 @@ import { EMPTY, of } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
3
  import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
+ import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
5
6
  import { fetchJeSchedulesPage, updateJESchedulesUIState, } from '../../reducers/jeSchedulesViewReducer';
6
7
  export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(updateJESchedulesUIState.match), filter((action) => action.payload.selectedPageTab != null), mergeMap(() => {
7
8
  const state = state$.value;
@@ -24,5 +25,9 @@ export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filt
24
25
  if (timePeriodStart == null || timePeriodEnd == null) {
25
26
  return EMPTY;
26
27
  }
28
+ const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
29
+ if (selectedPageTab === 'actual_matching') {
30
+ return of(fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, true));
31
+ }
27
32
  return of(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, true));
28
33
  }));
@@ -4,6 +4,7 @@ import { getMonthEndCloseChecksForATenantForSelectedPeriod } from '../../entity/
4
4
  import { getCurrentTenant, } from '../../entity/tenant/tenantSelector';
5
5
  import { getCompanyMonthEndReportSelectorView } from '../companyMonthEndReportView/companyMonthEndReportViewSelector';
6
6
  import { getMonthEndCloseChecksViewByTenantId, isMonthEndInsightDisabled, } from '../monthEndCloseChecksView/monthEndCloseChecksViewSelector';
7
+ import { getExpenseAutomationActualMatchingView } from './selectors/actualMatchingViewSelector';
7
8
  import { getExpenseAutomationFluxAnalysisView } from './selectors/fluxAnalysisViewSelector';
8
9
  import { getAllSteps } from './selectors/getAllStepsHelper';
9
10
  import { getExpenseAutomationJESchedulesView } from './selectors/jeSchedulesViewSelector';
@@ -21,7 +22,7 @@ const isPreviousStepDisabled = (selectedTransactionCategorizationTab, allSteps,
21
22
  return allSteps[stepIndex - 1].isDisabled;
22
23
  };
23
24
  export function getExpenseAutomationView(state) {
24
- const { expenseAutomationViewState, tenantState, expenseAutomationMissingReceiptsViewState, expenseAutomationJESchedulesViewState, expenseAutomationTransactionsViewState, expenseAutomationReconciliationViewState, monthEndCloseChecksState, companyState, } = state;
25
+ const { expenseAutomationViewState, tenantState, expenseAutomationMissingReceiptsViewState, expenseAutomationJESchedulesViewState, expenseAutomationActualMatchingViewState, expenseAutomationTransactionsViewState, expenseAutomationReconciliationViewState, monthEndCloseChecksState, companyState, } = state;
25
26
  const { loggedInUser, currentTenantId } = tenantState;
26
27
  const currentTenant = getCurrentTenant(state);
27
28
  const { currentSelectedView, selectedPeriodByTenantId } = expenseAutomationViewState;
@@ -42,6 +43,8 @@ export function getExpenseAutomationView(state) {
42
43
  const reconciliation = getExpenseAutomationReconciliationView(state);
43
44
  const expenseAutomationTransactionsView = getExpenseAutomationTransactionView(state);
44
45
  const jeSchedules = getExpenseAutomationJESchedulesView(state);
46
+ // Top-level sibling of `jeSchedules`: see ExpenseAutomationViewSelector.
47
+ const actualMatching = getExpenseAutomationActualMatchingView(state);
45
48
  switch (currentSelectedView) {
46
49
  case 'reconciliation':
47
50
  currentSelectedViewFetchState = reconciliation.fetchStatus;
@@ -54,12 +57,23 @@ export function getExpenseAutomationView(state) {
54
57
  fluxAnalysis.refreshStatus;
55
58
  break;
56
59
  case 'je_schedules':
57
- currentSelectedViewFetchState = {
58
- fetchState: jeSchedules.fetchState,
59
- error: jeSchedules.error,
60
- };
61
- currentSelectedViewBackgroundRefreshFetchState =
62
- jeSchedules.refreshStatus;
60
+ if (expenseAutomationJESchedulesViewState.uiState.selectedPageTab ===
61
+ 'actual_matching') {
62
+ currentSelectedViewFetchState = {
63
+ fetchState: actualMatching.fetchState,
64
+ error: actualMatching.error,
65
+ };
66
+ currentSelectedViewBackgroundRefreshFetchState =
67
+ actualMatching.refreshStatus;
68
+ }
69
+ else {
70
+ currentSelectedViewFetchState = {
71
+ fetchState: jeSchedules.fetchState,
72
+ error: jeSchedules.error,
73
+ };
74
+ currentSelectedViewBackgroundRefreshFetchState =
75
+ jeSchedules.refreshStatus;
76
+ }
63
77
  break;
64
78
  case 'missing_receipts':
65
79
  currentSelectedViewFetchState = {
@@ -91,6 +105,7 @@ export function getExpenseAutomationView(state) {
91
105
  const fetchStateVariables = [
92
106
  expenseAutomationMissingReceiptsViewState,
93
107
  expenseAutomationJESchedulesViewState,
108
+ expenseAutomationActualMatchingViewState,
94
109
  expenseAutomationTransactionsView,
95
110
  expenseAutomationReconciliationViewState,
96
111
  ];
@@ -176,6 +191,7 @@ export function getExpenseAutomationView(state) {
176
191
  ]);
177
192
  return {
178
193
  jeSchedules,
194
+ actualMatching,
179
195
  transactionView: expenseAutomationTransactionsView,
180
196
  missingReceipts,
181
197
  reconciliation,
@@ -1,5 +1,5 @@
1
- import { stringToUnion } from '../../commonStateTypes/stringToUnion';
2
- export const EXPENSE_AUTOMATION_VIEW_TYPES = [
1
+ import { stringToUnion, stringToUnionStrict, } from '../../commonStateTypes/stringToUnion';
2
+ const EXPENSE_AUTOMATION_VIEW_TYPES = [
3
3
  'transaction_categorization',
4
4
  'je_schedules',
5
5
  'reconciliation',
@@ -8,3 +8,5 @@ export const EXPENSE_AUTOMATION_VIEW_TYPES = [
8
8
  'month_end_insights',
9
9
  ];
10
10
  export const toExpenseAutomationViewType = (v) => stringToUnion(v, EXPENSE_AUTOMATION_VIEW_TYPES);
11
+ /** Unlike `toExpenseAutomationViewType`, unknown strings return `undefined`. */
12
+ export const toExpenseAutomationViewTypeStrict = (v) => stringToUnionStrict(v, EXPENSE_AUTOMATION_VIEW_TYPES);
@@ -0,0 +1,68 @@
1
+ import { toString } from '../../../commonStateTypes/timePeriod';
2
+ import { toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from '../types/actualMatchingViewState';
3
+ export function toServiceMonthFromPeriod(period) {
4
+ return toString(period.start).slice(0, 7);
5
+ }
6
+ const DEFAULT_CURRENCY_CODE = 'USD';
7
+ const DEFAULT_CURRENCY_SYMBOL = '$';
8
+ function resolveMatchSearchAmount(payload) {
9
+ const raw = payload.total_amount ?? payload.amount;
10
+ if (typeof raw === 'number' && Number.isFinite(raw)) {
11
+ return raw;
12
+ }
13
+ if (typeof raw === 'string' && raw !== '') {
14
+ const parsed = Number(raw);
15
+ if (Number.isFinite(parsed)) {
16
+ return parsed;
17
+ }
18
+ }
19
+ return 0;
20
+ }
21
+ function resolveMatchSearchCurrencySymbol(payload, currencyCode) {
22
+ if (payload.currency_symbol != null && payload.currency_symbol !== '') {
23
+ return payload.currency_symbol;
24
+ }
25
+ return currencyCode === DEFAULT_CURRENCY_CODE
26
+ ? DEFAULT_CURRENCY_SYMBOL
27
+ : currencyCode;
28
+ }
29
+ export function toActualMatchingTransactionSearchResult(payload) {
30
+ const currencyCode = payload.currency_code != null && payload.currency_code !== ''
31
+ ? payload.currency_code
32
+ : DEFAULT_CURRENCY_CODE;
33
+ return {
34
+ transactionId: payload.transaction_id,
35
+ transactionIntegrationId: payload.transaction_integration_id,
36
+ transactionType: payload.transaction_type,
37
+ lineId: payload.line_id,
38
+ vendorId: payload.vendor_id ?? undefined,
39
+ vendorName: payload.vendor_name ?? '',
40
+ amount: resolveMatchSearchAmount(payload),
41
+ transactionDate: payload.transaction_date,
42
+ accountId: payload.account_id ?? undefined,
43
+ accountName: payload.account_name ?? undefined,
44
+ accountDescription: payload.account_description ?? undefined,
45
+ accountingClassId: payload.accounting_class_id ?? undefined,
46
+ accountingClassName: payload.accounting_class_name ?? undefined,
47
+ currencyCode,
48
+ currencySymbol: resolveMatchSearchCurrencySymbol(payload, currencyCode),
49
+ transactionMemo: payload.transaction_memo ?? undefined,
50
+ transactionDescription: payload.transaction_description ?? undefined,
51
+ transactionTypeName: payload.transaction_type_name ?? undefined,
52
+ syncToken: payload.sync_token == null ? '' : String(payload.sync_token),
53
+ };
54
+ }
55
+ export function toMatchAndReverseResult(payload) {
56
+ return {
57
+ accrualId: payload.accrual_id,
58
+ status: toMatchAndReverseResultStatus(payload.status),
59
+ reason: payload.reason ?? undefined,
60
+ };
61
+ }
62
+ export function toUndoReversalResult(payload) {
63
+ return {
64
+ accrualId: payload.accrual_id,
65
+ status: toUndoReversalResultStatus(payload.status),
66
+ reason: payload.reason ?? undefined,
67
+ };
68
+ }
@@ -0,0 +1,371 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
3
+ import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
4
+ import { clearAll } from '../../../rootActions';
5
+ export const initialTransactionSearchState = {
6
+ query: '',
7
+ results: [],
8
+ fetchState: 'Not-Started',
9
+ error: undefined,
10
+ nextPageToken: null,
11
+ isLoadingMore: false,
12
+ };
13
+ export const initialAccrualSearchState = {
14
+ query: '',
15
+ results: [],
16
+ fetchState: 'Not-Started',
17
+ error: undefined,
18
+ nextPageToken: null,
19
+ isLoadingMore: false,
20
+ };
21
+ export const initialMatchModalState = {
22
+ isOpen: false,
23
+ openedFromMatchId: undefined,
24
+ pinnedTransactionResults: [],
25
+ transactionSearch: initialTransactionSearchState,
26
+ accrualSearch: initialAccrualSearchState,
27
+ confirmStatus: { fetchState: 'Not-Started', error: undefined },
28
+ };
29
+ export const initialState = {
30
+ matchIdsByPeriod: {},
31
+ fetchState: 'Not-Started',
32
+ error: undefined,
33
+ refreshStatus: {
34
+ fetchState: 'Not-Started',
35
+ error: undefined,
36
+ },
37
+ detailFetchStateByMatchId: {},
38
+ detailRefreshStatusByMatchId: {},
39
+ uiState: {
40
+ sortKey: 'date',
41
+ sortOrder: 'descending',
42
+ searchString: '',
43
+ scrollPosition: { scrollTop: 0, scrollLeft: undefined },
44
+ },
45
+ matchModal: initialMatchModalState,
46
+ undoReversalStatus: { fetchState: 'Not-Started', error: undefined },
47
+ hasValidState() {
48
+ return this.fetchState == 'Completed';
49
+ },
50
+ };
51
+ function resetMatchModalSearches(draft) {
52
+ draft.matchModal.transactionSearch = initialTransactionSearchState;
53
+ draft.matchModal.accrualSearch = initialAccrualSearchState;
54
+ draft.matchModal.confirmStatus = {
55
+ fetchState: 'Not-Started',
56
+ error: undefined,
57
+ };
58
+ draft.matchModal.lastBatchResults = undefined;
59
+ draft.matchModal.openedFromMatchId = undefined;
60
+ draft.matchModal.pinnedTransactionResults = [];
61
+ }
62
+ const expenseAutomationActualMatchingView = createSlice({
63
+ name: 'expenseAutomationActualMatchingView',
64
+ initialState,
65
+ reducers: {
66
+ fetchActualMatchingPage: {
67
+ prepare(period, refreshViewInBackground = false) {
68
+ return {
69
+ payload: {
70
+ period,
71
+ refreshViewInBackground,
72
+ },
73
+ };
74
+ },
75
+ reducer() {
76
+ // Epic-only fan-out.
77
+ },
78
+ },
79
+ fetchActualMatching: {
80
+ reducer(draft, action) {
81
+ const { refreshViewInBackground } = action.payload;
82
+ if (refreshViewInBackground) {
83
+ draft.refreshStatus = { fetchState: 'In-Progress', error: undefined };
84
+ }
85
+ else {
86
+ draft.fetchState = 'In-Progress';
87
+ draft.error = undefined;
88
+ }
89
+ },
90
+ prepare(period, refreshViewInBackground = false) {
91
+ return {
92
+ payload: {
93
+ period,
94
+ refreshViewInBackground,
95
+ },
96
+ };
97
+ },
98
+ },
99
+ fetchActualMatchingSuccess(draft, action) {
100
+ const { matchIds, selectedPeriod, refreshViewInBackground } = action.payload;
101
+ const periodId = toMonthYearPeriodId(selectedPeriod);
102
+ draft.matchIdsByPeriod[periodId] = matchIds;
103
+ if (refreshViewInBackground) {
104
+ draft.refreshStatus = { fetchState: 'Completed', error: undefined };
105
+ }
106
+ else {
107
+ draft.fetchState = 'Completed';
108
+ draft.error = undefined;
109
+ }
110
+ },
111
+ fetchActualMatchingFailure(draft, action) {
112
+ const { status, refreshViewInBackground } = action.payload;
113
+ if (refreshViewInBackground) {
114
+ draft.refreshStatus = { fetchState: 'Error', error: status };
115
+ }
116
+ else {
117
+ draft.fetchState = 'Error';
118
+ draft.error = status;
119
+ }
120
+ },
121
+ fetchActualMatchingMatch: {
122
+ prepare(matchId, refreshViewInBackground = false) {
123
+ return { payload: { matchId, refreshViewInBackground } };
124
+ },
125
+ reducer(draft, action) {
126
+ const { matchId, refreshViewInBackground } = action.payload;
127
+ if (refreshViewInBackground) {
128
+ draft.detailRefreshStatusByMatchId[matchId] = {
129
+ fetchState: 'In-Progress',
130
+ error: undefined,
131
+ };
132
+ }
133
+ else {
134
+ draft.detailFetchStateByMatchId[matchId] = {
135
+ fetchState: 'In-Progress',
136
+ error: undefined,
137
+ };
138
+ }
139
+ },
140
+ },
141
+ fetchActualMatchingMatchSuccess(draft, action) {
142
+ const { matchId, refreshViewInBackground } = action.payload;
143
+ if (refreshViewInBackground) {
144
+ draft.detailRefreshStatusByMatchId[matchId] = {
145
+ fetchState: 'Completed',
146
+ error: undefined,
147
+ };
148
+ }
149
+ else {
150
+ draft.detailFetchStateByMatchId[matchId] = {
151
+ fetchState: 'Completed',
152
+ error: undefined,
153
+ };
154
+ }
155
+ },
156
+ fetchActualMatchingMatchFailure(draft, action) {
157
+ const { matchId, refreshViewInBackground, status } = action.payload;
158
+ if (refreshViewInBackground) {
159
+ draft.detailRefreshStatusByMatchId[matchId] = {
160
+ fetchState: 'Error',
161
+ error: status,
162
+ };
163
+ }
164
+ else {
165
+ draft.detailFetchStateByMatchId[matchId] = {
166
+ fetchState: 'Error',
167
+ error: status,
168
+ };
169
+ }
170
+ },
171
+ updateActualMatchingUIState(draft, action) {
172
+ if (action.payload.sortKey != null) {
173
+ draft.uiState.sortKey = action.payload.sortKey;
174
+ }
175
+ if (action.payload.sortOrder != null) {
176
+ draft.uiState.sortOrder = action.payload.sortOrder;
177
+ }
178
+ if (action.payload.searchString != null) {
179
+ draft.uiState.searchString = action.payload.searchString;
180
+ }
181
+ if (action.payload.scrollPosition != null) {
182
+ draft.uiState.scrollPosition = action.payload.scrollPosition;
183
+ }
184
+ },
185
+ openMatchNewModal: {
186
+ prepare(matchId) {
187
+ return { payload: { matchId } };
188
+ },
189
+ reducer(draft, action) {
190
+ resetMatchModalSearches(draft);
191
+ draft.matchModal.isOpen = true;
192
+ const matchId = action.payload.matchId;
193
+ draft.matchModal.openedFromMatchId =
194
+ matchId != null && matchId !== '' ? matchId : undefined;
195
+ if (draft.matchModal.openedFromMatchId != null) {
196
+ draft.matchModal.accrualSearch.fetchState = 'Completed';
197
+ }
198
+ },
199
+ },
200
+ // Dismiss (Cancel / overlay). Store reset matches `clearMatchNewModal`;
201
+ // the actions stay distinct so confirm-success vs user-dismiss stay observable.
202
+ closeMatchNewModal(draft) {
203
+ draft.matchModal.isOpen = false;
204
+ resetMatchModalSearches(draft);
205
+ },
206
+ // Confirm-success / host reset. Same slice write as close; different action type.
207
+ clearMatchNewModal(draft) {
208
+ draft.matchModal.isOpen = false;
209
+ resetMatchModalSearches(draft);
210
+ },
211
+ searchMatchTransactions: {
212
+ reducer(draft, action) {
213
+ const { query, pageToken } = action.payload;
214
+ const isLoadMore = pageToken != null;
215
+ draft.matchModal.transactionSearch.query = query;
216
+ if (isLoadMore) {
217
+ draft.matchModal.transactionSearch.isLoadingMore = true;
218
+ }
219
+ else {
220
+ draft.matchModal.transactionSearch.isLoadingMore = false;
221
+ draft.matchModal.transactionSearch.results = [];
222
+ draft.matchModal.transactionSearch.nextPageToken = null;
223
+ draft.matchModal.transactionSearch.fetchState = 'In-Progress';
224
+ draft.matchModal.transactionSearch.error = undefined;
225
+ }
226
+ },
227
+ prepare({ query, pageToken, transactionType, transactionIntegrationId, }) {
228
+ return {
229
+ payload: {
230
+ query,
231
+ pageToken: pageToken ?? undefined,
232
+ transactionType,
233
+ transactionIntegrationId,
234
+ },
235
+ };
236
+ },
237
+ },
238
+ searchMatchTransactionsSuccess(draft, action) {
239
+ const { append, nextPageToken, results } = action.payload;
240
+ if (append) {
241
+ const merged = [
242
+ ...draft.matchModal.transactionSearch.results,
243
+ ...results,
244
+ ];
245
+ const byKey = new Map(merged.map((result) => [
246
+ `${result.transactionId}:${result.lineId}`,
247
+ result,
248
+ ]));
249
+ draft.matchModal.transactionSearch.results = Array.from(byKey.values());
250
+ }
251
+ else {
252
+ draft.matchModal.transactionSearch.results = results;
253
+ if (draft.matchModal.openedFromMatchId != null &&
254
+ draft.matchModal.pinnedTransactionResults.length === 0) {
255
+ draft.matchModal.pinnedTransactionResults = results;
256
+ }
257
+ }
258
+ draft.matchModal.transactionSearch.nextPageToken = nextPageToken;
259
+ draft.matchModal.transactionSearch.isLoadingMore = false;
260
+ draft.matchModal.transactionSearch.fetchState = 'Completed';
261
+ draft.matchModal.transactionSearch.error = undefined;
262
+ },
263
+ searchMatchTransactionsFailure(draft, action) {
264
+ draft.matchModal.transactionSearch.isLoadingMore = false;
265
+ draft.matchModal.transactionSearch.fetchState = 'Error';
266
+ draft.matchModal.transactionSearch.error = action.payload.error;
267
+ },
268
+ searchMatchAccruals: {
269
+ reducer(draft, action) {
270
+ const { query, pageToken } = action.payload;
271
+ const isLoadMore = pageToken != null;
272
+ draft.matchModal.accrualSearch.query = query;
273
+ if (isLoadMore) {
274
+ draft.matchModal.accrualSearch.isLoadingMore = true;
275
+ }
276
+ else {
277
+ draft.matchModal.accrualSearch.isLoadingMore = false;
278
+ draft.matchModal.accrualSearch.results = [];
279
+ draft.matchModal.accrualSearch.nextPageToken = null;
280
+ draft.matchModal.accrualSearch.fetchState = 'In-Progress';
281
+ draft.matchModal.accrualSearch.error = undefined;
282
+ }
283
+ },
284
+ prepare({ query, pageToken }) {
285
+ return { payload: { query, pageToken: pageToken ?? undefined } };
286
+ },
287
+ },
288
+ searchMatchAccrualsSuccess(draft, action) {
289
+ const { append, nextPageToken, results } = action.payload;
290
+ const keys = results.map((accrual) => generateJEOneTimeAccrualKey(accrual._id));
291
+ if (append) {
292
+ const merged = [...draft.matchModal.accrualSearch.results, ...keys];
293
+ draft.matchModal.accrualSearch.results = Array.from(new Set(merged));
294
+ }
295
+ else {
296
+ draft.matchModal.accrualSearch.results = keys;
297
+ }
298
+ draft.matchModal.accrualSearch.nextPageToken = nextPageToken;
299
+ draft.matchModal.accrualSearch.isLoadingMore = false;
300
+ draft.matchModal.accrualSearch.fetchState = 'Completed';
301
+ draft.matchModal.accrualSearch.error = undefined;
302
+ },
303
+ searchMatchAccrualsFailure(draft, action) {
304
+ draft.matchModal.accrualSearch.isLoadingMore = false;
305
+ draft.matchModal.accrualSearch.fetchState = 'Error';
306
+ draft.matchModal.accrualSearch.error = action.payload.error;
307
+ },
308
+ matchAndReverseAccruals: {
309
+ reducer(draft) {
310
+ draft.matchModal.confirmStatus = {
311
+ fetchState: 'In-Progress',
312
+ error: undefined,
313
+ };
314
+ },
315
+ prepare(params) {
316
+ return { payload: params };
317
+ },
318
+ },
319
+ matchAndReverseAccrualsSuccess(draft, action) {
320
+ draft.matchModal.confirmStatus = {
321
+ fetchState: 'Completed',
322
+ error: undefined,
323
+ };
324
+ draft.matchModal.lastBatchResults = action.payload.results;
325
+ },
326
+ matchAndReverseAccrualsFailure(draft, action) {
327
+ draft.matchModal.confirmStatus = {
328
+ fetchState: 'Error',
329
+ error: action.payload.status,
330
+ };
331
+ },
332
+ undoReversalAccruals: {
333
+ reducer(draft) {
334
+ draft.undoReversalStatus = {
335
+ fetchState: 'In-Progress',
336
+ error: undefined,
337
+ };
338
+ },
339
+ prepare(params) {
340
+ return { payload: params };
341
+ },
342
+ },
343
+ undoReversalAccrualsSuccess: {
344
+ reducer(draft) {
345
+ draft.undoReversalStatus = {
346
+ fetchState: 'Completed',
347
+ error: undefined,
348
+ };
349
+ },
350
+ prepare(payload) {
351
+ return { payload };
352
+ },
353
+ },
354
+ undoReversalAccrualsFailure(draft, action) {
355
+ draft.undoReversalStatus = {
356
+ fetchState: 'Error',
357
+ error: action.payload.status,
358
+ };
359
+ },
360
+ clearActualMatchingView(draft) {
361
+ Object.assign(draft, initialState);
362
+ },
363
+ },
364
+ extraReducers: (builder) => {
365
+ builder.addCase(clearAll, (draft) => {
366
+ Object.assign(draft, initialState);
367
+ });
368
+ },
369
+ });
370
+ export const { clearActualMatchingView, clearMatchNewModal, closeMatchNewModal, fetchActualMatching, fetchActualMatchingFailure, fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess, fetchActualMatchingPage, fetchActualMatchingSuccess, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, openMatchNewModal, searchMatchAccruals, searchMatchAccrualsFailure, searchMatchAccrualsSuccess, searchMatchTransactions, searchMatchTransactionsFailure, searchMatchTransactionsSuccess, undoReversalAccruals, undoReversalAccrualsFailure, undoReversalAccrualsSuccess, updateActualMatchingUIState, } = expenseAutomationActualMatchingView.actions;
371
+ export default expenseAutomationActualMatchingView.reducer;