@zeniai/client-epic-state 5.2.39 → 5.2.41-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 (124) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +31 -0
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +52 -0
  3. package/lib/entity/actualMatching/actualMatchingReducer.d.ts +9 -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 +23 -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/aiCfo/aiCfoReducer.js +78 -4
  12. package/lib/entity/aiCfo/aiCfoState.d.ts +16 -0
  13. package/lib/entity/file/fileReducer.d.ts +8 -0
  14. package/lib/entity/file/fileReducer.js +10 -2
  15. package/lib/entity/invoicing/invoicingCommonPayload.d.ts +14 -1
  16. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +31 -0
  17. package/lib/entity/jeSchedules/jeSchedulesPayload.js +53 -0
  18. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +33 -0
  19. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  20. package/lib/entity/snackbar/snackbarTypes.js +2 -0
  21. package/lib/epic.d.ts +8 -1
  22. package/lib/epic.js +14 -0
  23. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +48 -0
  24. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
  25. package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
  26. package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
  27. package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
  28. package/lib/esm/entity/aiCfo/aiCfoReducer.js +79 -5
  29. package/lib/esm/entity/file/fileReducer.js +10 -2
  30. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +53 -0
  31. package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
  32. package/lib/esm/epic.js +14 -0
  33. package/lib/esm/index.js +7 -3
  34. package/lib/esm/reducer.js +6 -0
  35. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +25 -12
  36. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingEpic.js +46 -0
  37. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +36 -0
  38. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingPageEpic.js +7 -0
  39. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +108 -0
  40. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/refreshActualMatchingList.js +16 -0
  41. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchAccrualsEpic.js +60 -0
  42. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchTransactionsEpic.js +74 -0
  43. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/undoReversalAccrualsEpic.js +78 -0
  44. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +13 -3
  45. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +40 -15
  46. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +19 -8
  47. package/lib/esm/view/expenseAutomationView/expenseAutomationViewReducer.js +2 -1
  48. package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +24 -6
  49. package/lib/esm/view/expenseAutomationView/expenseAutomationViewState.js +4 -2
  50. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
  51. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +462 -0
  52. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +2 -1
  53. package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
  54. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +426 -0
  55. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +4 -0
  56. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
  57. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -1
  58. package/lib/esm/view/financeStatement/financeStatementReducer.js +17 -27
  59. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +1 -1
  60. package/lib/esm/view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic.js +6 -0
  61. package/lib/esm/view/invoicing/settingsView/epics/saveInvoicingSettingsEpic.js +7 -0
  62. package/lib/esm/view/invoicing/settingsView/invoicingBrandingFormConfig.js +1 -1
  63. package/lib/esm/view/invoicing/settingsView/settingsViewSelector.js +5 -0
  64. package/lib/esm/view/invoicing/settingsView/submitInvoicingBrandingFormEpic.js +9 -0
  65. package/lib/index.d.ts +14 -5
  66. package/lib/index.js +82 -48
  67. package/lib/reducer.d.ts +2 -0
  68. package/lib/reducer.js +6 -0
  69. package/lib/rootStateTypes.d.ts +4 -0
  70. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +25 -12
  71. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
  72. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingEpic.js +50 -0
  73. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  74. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +40 -0
  75. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
  76. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingPageEpic.js +11 -0
  77. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.d.ts +9 -0
  78. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +112 -0
  79. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/refreshActualMatchingList.d.ts +3 -0
  80. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/refreshActualMatchingList.js +19 -0
  81. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchAccrualsEpic.d.ts +9 -0
  82. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchAccrualsEpic.js +64 -0
  83. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
  84. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchTransactionsEpic.js +78 -0
  85. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/undoReversalAccrualsEpic.d.ts +9 -0
  86. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/undoReversalAccrualsEpic.js +82 -0
  87. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.d.ts +2 -1
  88. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +13 -3
  89. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.d.ts +5 -1
  90. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +39 -14
  91. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +18 -7
  92. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.d.ts +2 -1
  93. package/lib/view/expenseAutomationView/expenseAutomationViewReducer.js +2 -1
  94. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +24 -6
  95. package/lib/view/expenseAutomationView/expenseAutomationViewState.d.ts +2 -1
  96. package/lib/view/expenseAutomationView/expenseAutomationViewState.js +6 -3
  97. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  98. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
  99. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
  100. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +79 -0
  101. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +466 -0
  102. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +6 -5
  103. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +2 -1
  104. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +87 -0
  105. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
  106. package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +11 -0
  107. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +38 -0
  108. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +445 -0
  109. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +4 -0
  110. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +106 -0
  111. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +46 -0
  112. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  113. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +8 -1
  114. package/lib/view/financeStatement/financeStatementReducer.js +17 -27
  115. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +1 -1
  116. package/lib/view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic.js +6 -0
  117. package/lib/view/invoicing/settingsView/epics/saveInvoicingSettingsEpic.js +7 -0
  118. package/lib/view/invoicing/settingsView/epics/settingsViewActionType.d.ts +2 -1
  119. package/lib/view/invoicing/settingsView/invoicingBrandingFormConfig.js +1 -1
  120. package/lib/view/invoicing/settingsView/settingsViewSelector.d.ts +8 -0
  121. package/lib/view/invoicing/settingsView/settingsViewSelector.js +5 -0
  122. package/lib/view/invoicing/settingsView/submitInvoicingBrandingFormEpic.d.ts +2 -1
  123. package/lib/view/invoicing/settingsView/submitInvoicingBrandingFormEpic.js +9 -0
  124. package/package.json +1 -1
@@ -2,24 +2,34 @@ import { concat, from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
3
  import { fetchAccountList } from '../../../accountList/accountListReducer';
4
4
  import { getAccountsTypesForScheduleEpics } from '../../../scheduleView/scheduleListView/scheduleListHelper';
5
+ import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
5
6
  import { fetchJeSchedules, fetchJeSchedulesPage, initializeAccountSettingsView, } from '../../reducers/jeSchedulesViewReducer';
6
7
  export const fetchJeSchedulesPageEpic = (actions$, state$) => actions$.pipe(filter(fetchJeSchedulesPage.match), mergeMap((action) => {
7
8
  const jeSchedulePageActions = [];
8
9
  const { period, refreshViewInBackground } = action.payload;
10
+ const state = state$.value;
11
+ const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
9
12
  const accountType = getAccountsTypesForScheduleEpics();
10
- const accountListState = state$.value.accountListState;
13
+ const accountListState = state.accountListState;
11
14
  if (accountListState.byReportId[accountType.accountListKey].fetchState ===
12
15
  'Not-Started') {
13
16
  // call this only if the account list for schedules is not fetched already
14
17
  jeSchedulePageActions.push(fetchAccountList(accountType.accountListKey, true, false, false, false, accountType.allowedAccountList));
15
18
  }
16
- jeSchedulePageActions.push(fetchJeSchedules(period, refreshViewInBackground));
19
+ // AM is chrome on this page but a different endpoint. fetchJeSchedules with
20
+ // selectedPageTab === 'actual_matching' would hit /1.0/schedules and write a bogus cache slot.
21
+ if (selectedPageTab === 'actual_matching') {
22
+ jeSchedulePageActions.push(fetchActualMatchingPage(period, refreshViewInBackground));
23
+ }
24
+ else {
25
+ jeSchedulePageActions.push(fetchJeSchedules(period, refreshViewInBackground));
26
+ }
17
27
  // Only on the first page load. Account settings cannot change from a tab switch or a
18
28
  // refresh, and re-initializing puts accountSettingsView back to 'In-Progress' -- which the
19
29
  // page reads as "still loading" and answers with a full skeleton over rows it already has.
20
30
  // The action also resets localData, so re-dispatching it blindly would empty the settings
21
31
  // form until the refetch lands. Saving account settings still re-initializes explicitly.
22
- if (!state$.value.expenseAutomationJESchedulesViewState.accountSettings
32
+ if (!state.expenseAutomationJESchedulesViewState.accountSettings
23
33
  .hasLoadedAccountSettings) {
24
34
  jeSchedulePageActions.push(initializeAccountSettingsView());
25
35
  }
@@ -1,7 +1,8 @@
1
- import { EMPTY, of } from 'rxjs';
1
+ import { EMPTY, from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
3
  import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
+ import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
5
6
  import { fetchJeSchedules, fetchJeSchedulesPage, } from '../../reducers/jeSchedulesViewReducer';
6
7
  import { ALL_JE_PAGE_TABS, getJESchedulePeriodTabKey, } from '../../types/jeSchedulesViewState';
7
8
  /**
@@ -9,27 +10,51 @@ import { ALL_JE_PAGE_TABS, getJESchedulePeriodTabKey, } from '../../types/jeSche
9
10
  *
10
11
  * Listens for `fetchJeSchedulesPage` rather than `fetchJeSchedules` on purpose: the prefetch emits
11
12
  * `fetchJeSchedules`, so listening for that would make this epic feed itself.
13
+ *
14
+ * Review <-> Existing share `/1.0/schedules`. Actual Matching is a different endpoint; it is
15
+ * warmed with `fetchActualMatchingPage` when the page action carries `isAccrualEnabled`.
12
16
  */
13
17
  export const prefetchOtherJeSchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(fetchJeSchedulesPage.match), mergeMap((action) => {
14
18
  const state = state$.value;
15
- const { period } = action.payload;
19
+ const { period, isAccrualEnabled } = action.payload;
16
20
  const { selectedPageTab } = state.expenseAutomationJESchedulesViewState.uiState;
17
- const otherPageTab = ALL_JE_PAGE_TABS.find((pageTab) => pageTab !== selectedPageTab);
18
- if (otherPageTab == null) {
19
- return EMPTY;
20
- }
21
+ const actions = [];
22
+ // AM is chrome-only on ALL_JE_PAGE_TABS; warming it with fetchJeSchedules
23
+ // would hit the wrong endpoint. Warm every other JE tab, not just the first
24
+ // in ALL_JE_PAGE_TABS — from AM that first hit is always Review, and Existing
25
+ // would never prefetch.
26
+ const otherJeTabs = ALL_JE_PAGE_TABS.filter((pageTab) => pageTab !== selectedPageTab && pageTab !== 'actual_matching');
21
27
  const currentTenant = getCurrentTenant(state);
22
28
  const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
23
- if (selectedPeriod == null) {
24
- return EMPTY;
29
+ if (selectedPeriod != null) {
30
+ otherJeTabs.forEach((otherPageTab) => {
31
+ const otherPeriodTabKey = getJESchedulePeriodTabKey(otherPageTab, toMonthYearPeriodId(selectedPeriod));
32
+ const isOtherTabAlreadyLoaded = state.expenseAutomationJESchedulesViewState
33
+ .jeScheduleTransactionKeysByPeriodAndTab[otherPeriodTabKey] !=
34
+ null;
35
+ if (!isOtherTabAlreadyLoaded) {
36
+ actions.push(fetchJeSchedules(period, true, otherPageTab));
37
+ }
38
+ });
39
+ }
40
+ // GET /actual-matching is not Statsig-gated; CES has no Statsig. The screen
41
+ // passes is_accrual_enabled so disabled tenants do not pay for a list they
42
+ // cannot open. Visible AM is fetchJeSchedulesPageEpic's job.
43
+ if (isAccrualEnabled === true &&
44
+ selectedPageTab !== 'actual_matching') {
45
+ const periodId = toMonthYearPeriodId({
46
+ month: period.start.month,
47
+ year: period.start.year,
48
+ });
49
+ // `fetchState` is global across months. Skipping on In-Progress would drop
50
+ // October prefetch while September is still loading; September's success
51
+ // then marks the slice Completed and October looks loaded with no ids.
52
+ if (state.expenseAutomationActualMatchingViewState.matchIdsByPeriod[periodId] == null) {
53
+ actions.push(fetchActualMatchingPage(period, true));
54
+ }
25
55
  }
26
- // Already warm for this period: without this check every tab switch would refetch the tab
27
- // just left, since a switch also fires fetchJeSchedulesPage.
28
- const otherPeriodTabKey = getJESchedulePeriodTabKey(otherPageTab, toMonthYearPeriodId(selectedPeriod));
29
- const isOtherTabAlreadyLoaded = state.expenseAutomationJESchedulesViewState
30
- .jeScheduleTransactionKeysByPeriodAndTab[otherPeriodTabKey] != null;
31
- if (isOtherTabAlreadyLoaded) {
56
+ if (actions.length === 0) {
32
57
  return EMPTY;
33
58
  }
34
- return of(fetchJeSchedules(period, true, otherPageTab));
59
+ return from(actions);
35
60
  }));
@@ -1,23 +1,34 @@
1
1
  import { EMPTY, of } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
- import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
3
+ import { convertToPeriod, toAbsoluteDay, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
5
  import { fetchJeSchedulesPage, updateJESchedulesUIState, } from '../../reducers/jeSchedulesViewReducer';
6
- export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(updateJESchedulesUIState.match), filter((action) => action.payload.selectedPageTab != null), mergeMap(() => {
6
+ import { getJESchedulePeriodTabKey } from '../../types/jeSchedulesViewState';
7
+ export const switchJESchedulesTabEpic = (actions$, state$) => actions$.pipe(filter(updateJESchedulesUIState.match), filter((action) => action.payload.selectedPageTab != null), mergeMap((action) => {
7
8
  const state = state$.value;
8
- const { fetchState, refreshStatus } = state.expenseAutomationJESchedulesViewState;
9
- if (fetchState === 'In-Progress' ||
10
- refreshStatus.fetchState === 'In-Progress') {
11
- return EMPTY;
12
- }
9
+ const nextTab = action.payload.selectedPageTab;
13
10
  const currentTenant = getCurrentTenant(state);
14
11
  const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
15
12
  // convertToPeriod destructures, so an unset period throws and takes this epic's subscription
16
13
  // down for the rest of the session -- every later tab switch would then stop refreshing. A
17
14
  // skipped refresh is the cheaper failure, as in refreshCurrentPage.
18
- if (selectedPeriod == null) {
15
+ if (selectedPeriod == null || nextTab == null) {
19
16
  return EMPTY;
20
17
  }
18
+ const { fetchState, refreshStatus, jeScheduleTransactionKeysByPeriodAndTab } = state.expenseAutomationJESchedulesViewState;
19
+ // Review/Existing share `/1.0/schedules` but not a cache slot. A Review
20
+ // prefetch must not skip Existing when Existing has no keys yet — AM→Existing
21
+ // would sit on a skeleton with no request. Skip only when this tab is warm.
22
+ // AM is a different endpoint — never block it on JE In-Progress.
23
+ if (nextTab !== 'actual_matching') {
24
+ const slotKey = getJESchedulePeriodTabKey(nextTab, toMonthYearPeriodId(selectedPeriod));
25
+ const slotLoaded = jeScheduleTransactionKeysByPeriodAndTab[slotKey] != null;
26
+ if (slotLoaded &&
27
+ (fetchState === 'In-Progress' ||
28
+ refreshStatus.fetchState === 'In-Progress')) {
29
+ return EMPTY;
30
+ }
31
+ }
21
32
  const period = convertToPeriod(selectedPeriod);
22
33
  const timePeriodStart = toAbsoluteDay(period.start);
23
34
  const timePeriodEnd = toAbsoluteDay(period.end);
@@ -19,11 +19,12 @@ const expenseAutomationView = createSlice({
19
19
  reducer() {
20
20
  //do nothing
21
21
  },
22
- prepare(cacheOverride = false, refreshViewInBackground = false) {
22
+ prepare(cacheOverride = false, refreshViewInBackground = false, isAccrualEnabled = false) {
23
23
  return {
24
24
  payload: {
25
25
  cacheOverride,
26
26
  refreshViewInBackground,
27
+ isAccrualEnabled,
27
28
  },
28
29
  };
29
30
  },
@@ -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';
@@ -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 = {
@@ -88,6 +102,9 @@ export function getExpenseAutomationView(state) {
88
102
  };
89
103
  break;
90
104
  }
105
+ // AM is optional (flag-off / background prefetch) and must not keep the
106
+ // page-level AND-complete fetchState stuck on Not-Started. Tab chrome uses
107
+ // currentSelectedViewFetchState, which already switches to AM when selected.
91
108
  const fetchStateVariables = [
92
109
  expenseAutomationMissingReceiptsViewState,
93
110
  expenseAutomationJESchedulesViewState,
@@ -176,6 +193,7 @@ export function getExpenseAutomationView(state) {
176
193
  ]);
177
194
  return {
178
195
  jeSchedules,
196
+ actualMatching,
179
197
  transactionView: expenseAutomationTransactionsView,
180
198
  missingReceipts,
181
199
  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
+ function resolveMatchSearchAmount(payload) {
7
+ const raw = payload.total_amount ?? payload.amount;
8
+ if (typeof raw === 'number' && Number.isFinite(raw)) {
9
+ return raw;
10
+ }
11
+ if (typeof raw === 'string' && raw !== '') {
12
+ const parsed = Number(raw);
13
+ if (Number.isFinite(parsed)) {
14
+ return parsed;
15
+ }
16
+ }
17
+ return 0;
18
+ }
19
+ function resolveMatchSearchCurrencySymbol(payload, currencyCode, fallbackCurrency) {
20
+ if (payload.currency_symbol != null && payload.currency_symbol !== '') {
21
+ return payload.currency_symbol;
22
+ }
23
+ if (fallbackCurrency != null &&
24
+ currencyCode === fallbackCurrency.currencyCode) {
25
+ return fallbackCurrency.currencySymbol;
26
+ }
27
+ return currencyCode;
28
+ }
29
+ export function toActualMatchingTransactionSearchResult(payload, fallbackCurrency) {
30
+ const currencyCode = payload.currency_code != null && payload.currency_code !== ''
31
+ ? payload.currency_code
32
+ : fallbackCurrency?.currencyCode ?? '';
33
+ return {
34
+ transactionId: payload.transaction_id,
35
+ transactionIntegrationId: payload.transaction_integration_id,
36
+ transactionType: (payload.transaction_type || '').toLowerCase(),
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, fallbackCurrency),
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
+ }