@zeniai/client-epic-state 5.2.34-beta0ND → 5.2.35-beta0MM
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/entity/actualMatching/actualMatchingPayload.d.ts +25 -0
- package/lib/entity/actualMatching/actualMatchingPayload.js +43 -0
- package/lib/entity/actualMatching/actualMatchingReducer.d.ts +8 -0
- package/lib/entity/actualMatching/actualMatchingReducer.js +33 -0
- package/lib/entity/actualMatching/actualMatchingSelector.d.ts +3 -0
- package/lib/entity/actualMatching/actualMatchingSelector.js +6 -0
- package/lib/entity/actualMatching/actualMatchingState.d.ts +22 -0
- package/lib/entity/actualMatching/actualMatchingState.js +2 -0
- package/lib/entity/actualMatching/actualMatchingTypes.d.ts +1 -0
- package/lib/entity/actualMatching/actualMatchingTypes.js +2 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +29 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +49 -0
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +31 -0
- package/lib/entity/notificationRegistry/notificationRegistryReducer.d.ts +1 -2
- package/lib/entity/notificationRegistry/notificationRegistryReducer.js +9 -20
- package/lib/entity/notificationRegistry/notificationRegistrySelector.d.ts +1 -2
- package/lib/entity/notificationRegistry/notificationRegistrySelector.js +1 -7
- package/lib/entity/notificationRegistry/notificationRegistryState.d.ts +0 -5
- package/lib/entity/notificationRegistry/notificationRegistryState.js +1 -7
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +1 -3
- package/lib/epic.d.ts +8 -1
- package/lib/epic.js +18 -4
- package/lib/esm/entity/actualMatching/actualMatchingPayload.js +40 -0
- package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
- package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
- package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
- package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +49 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistryReducer.js +9 -20
- package/lib/esm/entity/notificationRegistry/notificationRegistrySelector.js +0 -5
- package/lib/esm/entity/notificationRegistry/notificationRegistryState.js +0 -5
- package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +1 -3
- package/lib/esm/epic.js +18 -4
- package/lib/esm/index.js +10 -6
- package/lib/esm/reducer.js +6 -0
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +2 -4
- package/lib/esm/view/aiCfoView/epics/fetchRoutineRunsEpic.js +1 -3
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +46 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +52 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +44 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +73 -0
- package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +52 -0
- package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
- package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
- package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
- package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +364 -0
- package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +281 -0
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
- package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +32 -0
- package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
- package/lib/esm/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +7 -20
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewReducer.js +17 -43
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewSelector.js +4 -24
- package/lib/esm/view/settingsView/epic/fetchNotificationSettingsEpic.js +2 -12
- package/lib/index.d.ts +16 -8
- package/lib/index.js +78 -55
- package/lib/reducer.d.ts +2 -0
- package/lib/reducer.js +6 -0
- package/lib/rootStateTypes.d.ts +4 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.js +2 -4
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -1
- package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.js +1 -3
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +50 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +56 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +77 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +56 -0
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
- package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +74 -0
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +368 -0
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +4 -4
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +83 -0
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
- package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +2 -0
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +29 -0
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +296 -0
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +99 -0
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +6 -19
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.d.ts +5 -8
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.js +17 -43
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.d.ts +0 -4
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.js +5 -30
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.d.ts +3 -4
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.js +2 -12
- package/lib/view/settingsView/settingsViewPayload.d.ts +0 -2
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap, takeUntil, } from 'rxjs/operators';
|
|
3
|
+
import { updateActualMatchingMatches } from '../../../../entity/actualMatching/actualMatchingReducer';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
|
+
import { clearAll } from '../../../../rootActions';
|
|
7
|
+
import { toServiceMonthFromPeriod, } from '../../payload/actualMatchingPayload';
|
|
8
|
+
import { fetchActualMatching, fetchActualMatchingFailure, fetchActualMatchingSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
9
|
+
export const fetchActualMatchingEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchActualMatching.match), switchMap((action) => {
|
|
10
|
+
const state = state$.value;
|
|
11
|
+
const { period, refreshViewInBackground } = action.payload;
|
|
12
|
+
const currentTenant = getCurrentTenant(state);
|
|
13
|
+
const selectedPeriod = state.expenseAutomationViewState
|
|
14
|
+
.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''] ?? {
|
|
15
|
+
month: period.start.month,
|
|
16
|
+
year: period.start.year,
|
|
17
|
+
};
|
|
18
|
+
const serviceMonth = toServiceMonthFromPeriod(period);
|
|
19
|
+
return zeniAPI
|
|
20
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/actual-matching?service_month=${encodeURIComponent(serviceMonth)}`)
|
|
21
|
+
.pipe(mergeMap((response) => {
|
|
22
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
23
|
+
const matches = response.data.matches;
|
|
24
|
+
const updateActions = [];
|
|
25
|
+
if (matches.length > 0) {
|
|
26
|
+
updateActions.push(updateActualMatchingMatches(matches));
|
|
27
|
+
}
|
|
28
|
+
updateActions.push(fetchActualMatchingSuccess({
|
|
29
|
+
matchIds: matches.map((match) => match.match_id),
|
|
30
|
+
selectedPeriod,
|
|
31
|
+
refreshViewInBackground,
|
|
32
|
+
}));
|
|
33
|
+
return from(updateActions);
|
|
34
|
+
}
|
|
35
|
+
return of(fetchActualMatchingFailure({
|
|
36
|
+
status: response.status,
|
|
37
|
+
selectedPeriod,
|
|
38
|
+
refreshViewInBackground,
|
|
39
|
+
}));
|
|
40
|
+
}), catchError((error) => of(fetchActualMatchingFailure({
|
|
41
|
+
status: createZeniAPIStatus('Unexpected Error', 'fetch actual matching REST API call errored out' +
|
|
42
|
+
JSON.stringify(error)),
|
|
43
|
+
selectedPeriod,
|
|
44
|
+
refreshViewInBackground,
|
|
45
|
+
}))), takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
46
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { from } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
|
+
import { updateActualMatchingMatches } from '../../../../entity/actualMatching/actualMatchingReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { clearAll } from '../../../../rootActions';
|
|
6
|
+
import { fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
7
|
+
export const fetchActualMatchingMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchActualMatchingMatch.match), mergeMap((action) => {
|
|
8
|
+
const { matchId, refreshViewInBackground } = action.payload;
|
|
9
|
+
return zeniAPI
|
|
10
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/actual-matching/${encodeURIComponent(matchId)}`)
|
|
11
|
+
.pipe(mergeMap((response) => {
|
|
12
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
13
|
+
return from([
|
|
14
|
+
updateActualMatchingMatches([response.data]),
|
|
15
|
+
fetchActualMatchingMatchSuccess({
|
|
16
|
+
matchId,
|
|
17
|
+
refreshViewInBackground,
|
|
18
|
+
}),
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
return from([
|
|
22
|
+
fetchActualMatchingMatchFailure({
|
|
23
|
+
matchId,
|
|
24
|
+
refreshViewInBackground,
|
|
25
|
+
status: response.status,
|
|
26
|
+
}),
|
|
27
|
+
]);
|
|
28
|
+
}), catchError((error) => from([
|
|
29
|
+
fetchActualMatchingMatchFailure({
|
|
30
|
+
matchId,
|
|
31
|
+
refreshViewInBackground,
|
|
32
|
+
status: createZeniAPIStatus('Unexpected Error', `Fetch actual matching match REST API call errored out ${JSON.stringify(error)}`),
|
|
33
|
+
}),
|
|
34
|
+
])), takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
35
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { fetchActualMatching, fetchActualMatchingPage, } from '../../reducers/actualMatchingViewReducer';
|
|
4
|
+
export const fetchActualMatchingPageEpic = (actions$) => actions$.pipe(filter(fetchActualMatchingPage.match), mergeMap((action) => {
|
|
5
|
+
const { period, refreshViewInBackground } = action.payload;
|
|
6
|
+
return of(fetchActualMatching(period, refreshViewInBackground));
|
|
7
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
|
+
import { clearAll } from '../../../../rootActions';
|
|
7
|
+
import { toMatchAndReverseResult, } from '../../payload/actualMatchingPayload';
|
|
8
|
+
import { clearMatchNewModal, fetchActualMatching, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
9
|
+
function refreshActualMatchingList(state) {
|
|
10
|
+
const currentTenant = getCurrentTenant(state);
|
|
11
|
+
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''];
|
|
12
|
+
if (selectedMonthYear == null) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const period = convertToPeriod(selectedMonthYear);
|
|
16
|
+
const start = toAbsoluteDay(period.start);
|
|
17
|
+
const end = toAbsoluteDay(period.end);
|
|
18
|
+
if (start == null || end == null) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return [fetchActualMatching({ start, end }, true)];
|
|
22
|
+
}
|
|
23
|
+
export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(matchAndReverseAccruals.match), mergeMap((action) => {
|
|
24
|
+
const { transactionId, transactionIntegrationId, transactionType, lineId, accrualIds, transactionSyncToken, } = action.payload;
|
|
25
|
+
const body = {
|
|
26
|
+
transaction_id: transactionId,
|
|
27
|
+
transaction_integration_id: transactionIntegrationId,
|
|
28
|
+
transaction_type: transactionType,
|
|
29
|
+
line_id: lineId,
|
|
30
|
+
transaction_sync_token: transactionSyncToken,
|
|
31
|
+
accrual_ids: accrualIds,
|
|
32
|
+
};
|
|
33
|
+
return zeniAPI
|
|
34
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/match-and-reverse`, body)
|
|
35
|
+
.pipe(mergeMap((response) => {
|
|
36
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
37
|
+
const results = response.data.results.map(toMatchAndReverseResult);
|
|
38
|
+
const successActions = [
|
|
39
|
+
matchAndReverseAccrualsSuccess({ results }),
|
|
40
|
+
];
|
|
41
|
+
const anyReversed = results.some((result) => result.status === 'reversed');
|
|
42
|
+
if (anyReversed) {
|
|
43
|
+
successActions.push(...refreshActualMatchingList(state$.value), clearMatchNewModal());
|
|
44
|
+
}
|
|
45
|
+
return from(successActions);
|
|
46
|
+
}
|
|
47
|
+
return of(matchAndReverseAccrualsFailure({ status: response.status }));
|
|
48
|
+
}), catchError((error) => of(matchAndReverseAccrualsFailure({
|
|
49
|
+
status: createZeniAPIStatus('Unexpected Error', 'Match and reverse accruals REST API call errored out' +
|
|
50
|
+
JSON.stringify(error)),
|
|
51
|
+
}))), takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
52
|
+
}));
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { from, merge, of } from 'rxjs';
|
|
2
|
+
import { catchError, debounceTime, filter, mergeMap, switchMap, } from 'rxjs/operators';
|
|
3
|
+
import { updateJEOneTimeAccruals } from '../../../../entity/jeSchedules/jeSchedulesReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { searchMatchAccruals, searchMatchAccrualsFailure, searchMatchAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
6
|
+
import { MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, } from '../../types/actualMatchingViewState';
|
|
7
|
+
export const searchMatchAccrualsEpic = (actions$, _state$, zeniAPI) => {
|
|
8
|
+
const searchActions$ = actions$.pipe(filter(searchMatchAccruals.match));
|
|
9
|
+
const pagination$ = searchActions$.pipe(filter((action) => action.payload.pageToken != null));
|
|
10
|
+
const newSearchDebounced$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null), debounceTime(MATCH_SEARCH_DEBOUNCE_MS));
|
|
11
|
+
return merge(pagination$, newSearchDebounced$).pipe(switchMap((action) => {
|
|
12
|
+
const { query, pageToken } = action.payload;
|
|
13
|
+
const offset = pageToken != null && pageToken.length > 0 ? Number(pageToken) : 0;
|
|
14
|
+
const searchText = encodeURIComponent(query);
|
|
15
|
+
const limit = MATCH_ACCRUAL_SEARCH_LIMIT;
|
|
16
|
+
return zeniAPI
|
|
17
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals?status=posted&reversal_policy=on_bill_match&search_text=${searchText}&limit=${limit}&offset=${offset}`)
|
|
18
|
+
.pipe(mergeMap((response) => {
|
|
19
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
20
|
+
const accruals = response.data.accruals;
|
|
21
|
+
const append = pageToken != null;
|
|
22
|
+
const nextOffset = offset + accruals.length;
|
|
23
|
+
const total = response.data.total ?? nextOffset;
|
|
24
|
+
const nextPageToken = nextOffset < total ? String(nextOffset) : null;
|
|
25
|
+
const actionsOut = [];
|
|
26
|
+
if (accruals.length > 0) {
|
|
27
|
+
actionsOut.push(updateJEOneTimeAccruals(accruals));
|
|
28
|
+
}
|
|
29
|
+
actionsOut.push(searchMatchAccrualsSuccess({
|
|
30
|
+
append,
|
|
31
|
+
nextPageToken,
|
|
32
|
+
results: accruals,
|
|
33
|
+
}));
|
|
34
|
+
return from(actionsOut);
|
|
35
|
+
}
|
|
36
|
+
return of(searchMatchAccrualsFailure({
|
|
37
|
+
error: response.status,
|
|
38
|
+
}));
|
|
39
|
+
}), catchError((error) => of(searchMatchAccrualsFailure({
|
|
40
|
+
error: createZeniAPIStatus('Unexpected Error', 'Search match accruals REST API call errored out' +
|
|
41
|
+
JSON.stringify(error)),
|
|
42
|
+
}))));
|
|
43
|
+
}));
|
|
44
|
+
};
|
package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { from, merge, of } from 'rxjs';
|
|
2
|
+
import { catchError, debounceTime, filter, mergeMap, switchMap, } from 'rxjs/operators';
|
|
3
|
+
import { getActualMatchingMatchById } from '../../../../entity/actualMatching/actualMatchingSelector';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { toActualMatchingTransactionSearchResult, } from '../../payload/actualMatchingPayload';
|
|
6
|
+
import { openMatchNewModal, searchMatchAccruals, searchMatchTransactions, searchMatchTransactionsFailure, searchMatchTransactionsSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
7
|
+
import { parseActualMatchingMatchId } from '../../selectors/actualMatchingViewSelector';
|
|
8
|
+
import { MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, } from '../../types/actualMatchingViewState';
|
|
9
|
+
export const searchMatchTransactionsEpic = (actions$, state$, zeniAPI) => {
|
|
10
|
+
const openModal$ = actions$.pipe(filter(openMatchNewModal.match), mergeMap((action) => {
|
|
11
|
+
const matchId = action.payload.matchId;
|
|
12
|
+
if (matchId == null || matchId === '') {
|
|
13
|
+
return from([
|
|
14
|
+
searchMatchTransactions({ query: '' }),
|
|
15
|
+
searchMatchAccruals({ query: '' }),
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
const match = getActualMatchingMatchById(state$.value.actualMatchingState, matchId);
|
|
19
|
+
const parsed = parseActualMatchingMatchId(matchId);
|
|
20
|
+
const transactionType = match?.transactionType != null && match.transactionType !== ''
|
|
21
|
+
? match.transactionType
|
|
22
|
+
: parsed?.transactionType;
|
|
23
|
+
const transactionIntegrationId = match?.transactionIntegrationId != null &&
|
|
24
|
+
match.transactionIntegrationId !== ''
|
|
25
|
+
? match.transactionIntegrationId
|
|
26
|
+
: parsed?.transactionIntegrationId;
|
|
27
|
+
return from([
|
|
28
|
+
searchMatchTransactions({
|
|
29
|
+
query: '',
|
|
30
|
+
transactionType,
|
|
31
|
+
transactionIntegrationId,
|
|
32
|
+
}),
|
|
33
|
+
]);
|
|
34
|
+
}));
|
|
35
|
+
const searchActions$ = actions$.pipe(filter(searchMatchTransactions.match));
|
|
36
|
+
const pagination$ = searchActions$.pipe(filter((action) => action.payload.pageToken != null));
|
|
37
|
+
const newSearchDebounced$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null), debounceTime(MATCH_SEARCH_DEBOUNCE_MS));
|
|
38
|
+
const search$ = merge(pagination$, newSearchDebounced$).pipe(switchMap((action) => {
|
|
39
|
+
const { query, pageToken, transactionType, transactionIntegrationId } = action.payload;
|
|
40
|
+
const queryParam = {
|
|
41
|
+
search_text: query,
|
|
42
|
+
page_size: MATCH_TRANSACTION_SEARCH_PAGE_SIZE,
|
|
43
|
+
...(pageToken != null ? { page_token: pageToken } : {}),
|
|
44
|
+
...(transactionType != null && transactionType !== ''
|
|
45
|
+
? { transaction_type: transactionType }
|
|
46
|
+
: {}),
|
|
47
|
+
...(transactionIntegrationId != null && transactionIntegrationId !== ''
|
|
48
|
+
? { transaction_integration_id: transactionIntegrationId }
|
|
49
|
+
: {}),
|
|
50
|
+
};
|
|
51
|
+
return zeniAPI
|
|
52
|
+
.getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/match-transaction-search?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
|
|
53
|
+
.pipe(mergeMap((response) => {
|
|
54
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
55
|
+
const { transactions, next_page_token } = response.data;
|
|
56
|
+
const append = pageToken != null;
|
|
57
|
+
const results = transactions.map(toActualMatchingTransactionSearchResult);
|
|
58
|
+
return of(searchMatchTransactionsSuccess({
|
|
59
|
+
append,
|
|
60
|
+
nextPageToken: next_page_token ?? null,
|
|
61
|
+
results,
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
return of(searchMatchTransactionsFailure({
|
|
65
|
+
error: response.status,
|
|
66
|
+
}));
|
|
67
|
+
}), catchError((error) => of(searchMatchTransactionsFailure({
|
|
68
|
+
error: createZeniAPIStatus('Unexpected Error', 'Search match transactions REST API call errored out' +
|
|
69
|
+
JSON.stringify(error)),
|
|
70
|
+
}))));
|
|
71
|
+
}));
|
|
72
|
+
return merge(openModal$, search$);
|
|
73
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
|
+
import { clearAll } from '../../../../rootActions';
|
|
7
|
+
import { toUndoReversalResult, } from '../../payload/actualMatchingPayload';
|
|
8
|
+
import { fetchActualMatching, fetchActualMatchingMatch, undoReversalAccruals, undoReversalAccrualsFailure, undoReversalAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
|
|
9
|
+
function refreshActualMatchingList(state) {
|
|
10
|
+
const currentTenant = getCurrentTenant(state);
|
|
11
|
+
const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''];
|
|
12
|
+
if (selectedMonthYear == null) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const period = convertToPeriod(selectedMonthYear);
|
|
16
|
+
const start = toAbsoluteDay(period.start);
|
|
17
|
+
const end = toAbsoluteDay(period.end);
|
|
18
|
+
if (start == null || end == null) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return [fetchActualMatching({ start, end }, true)];
|
|
22
|
+
}
|
|
23
|
+
function refreshOpenMatchDetails(state) {
|
|
24
|
+
const detailState = state.expenseAutomationActualMatchingViewState.detailFetchStateByMatchId;
|
|
25
|
+
return Object.keys(detailState)
|
|
26
|
+
.filter((matchId) => detailState[matchId]?.fetchState !== 'Not-Started')
|
|
27
|
+
.map((matchId) => fetchActualMatchingMatch(matchId, true));
|
|
28
|
+
}
|
|
29
|
+
export const undoReversalAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(undoReversalAccruals.match), mergeMap((action) => {
|
|
30
|
+
const body = {
|
|
31
|
+
accrual_ids: action.payload.accrualIds,
|
|
32
|
+
};
|
|
33
|
+
return zeniAPI
|
|
34
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/undo-reversal`, body)
|
|
35
|
+
.pipe(mergeMap((response) => {
|
|
36
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
37
|
+
const results = response.data.results.map(toUndoReversalResult);
|
|
38
|
+
const successActions = [
|
|
39
|
+
undoReversalAccrualsSuccess({ results }),
|
|
40
|
+
];
|
|
41
|
+
const anyUndone = results.some((result) => result.status === 'undone');
|
|
42
|
+
if (anyUndone) {
|
|
43
|
+
successActions.push(...refreshActualMatchingList(state$.value), ...refreshOpenMatchDetails(state$.value));
|
|
44
|
+
}
|
|
45
|
+
return from(successActions);
|
|
46
|
+
}
|
|
47
|
+
return of(undoReversalAccrualsFailure({ status: response.status }));
|
|
48
|
+
}), catchError((error) => of(undoReversalAccrualsFailure({
|
|
49
|
+
status: createZeniAPIStatus('Unexpected Error', 'Undo reversal accruals REST API call errored out' +
|
|
50
|
+
JSON.stringify(error)),
|
|
51
|
+
}))), takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
52
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js
CHANGED
|
@@ -3,6 +3,7 @@ import { filter, switchMap } from 'rxjs/operators';
|
|
|
3
3
|
import { convertToPeriod, toAbsoluteDay, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
4
|
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
5
|
import { fetchAllExpenseAutomationTabs } from '../../expenseAutomationViewReducer';
|
|
6
|
+
import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
|
|
6
7
|
import { fetchFluxAnalysisView } from '../../reducers/fluxAnalysisViewReducer';
|
|
7
8
|
import { fetchJeSchedulesPage } from '../../reducers/jeSchedulesViewReducer';
|
|
8
9
|
import { fetchMissingReceipts } from '../../reducers/missingReceiptsViewReducer';
|
|
@@ -31,11 +32,14 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
|
|
|
31
32
|
}
|
|
32
33
|
if (cacheOverride === true) {
|
|
33
34
|
const actions = [];
|
|
35
|
+
const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
|
|
34
36
|
actions.push(fetchTransactionCategorizationView(selectedTransactionCategorizationTab, { start: timePeriodStart, end: timePeriodEnd }, cacheOverride, false, undefined, undefined, refreshViewInBackground, false), fetchMissingReceipts({ start: timePeriodStart, end: timePeriodEnd }, {
|
|
35
37
|
amount: 75.0,
|
|
36
38
|
currencyCode: 'USD',
|
|
37
39
|
currencySymbol: '$',
|
|
38
|
-
}, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null),
|
|
40
|
+
}, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null), selectedPageTab === 'actual_matching'
|
|
41
|
+
? fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride)
|
|
42
|
+
: fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
39
43
|
if (reconciliationEnabled) {
|
|
40
44
|
actions.push(fetchReconciliation(selectedPeriod, undefined, cacheOverride, refreshViewInBackground));
|
|
41
45
|
}
|
|
@@ -61,16 +65,29 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
|
|
|
61
65
|
fetchActions.push(fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null));
|
|
62
66
|
}
|
|
63
67
|
// The two JE tabs cache separately, so only the tab actually being shown decides whether a
|
|
64
|
-
// fetch is still needed.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
state.
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
// fetch is still needed. Actual Matching is a third tab on the same page with its own
|
|
69
|
+
// endpoint and cache slot.
|
|
70
|
+
const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
|
|
71
|
+
if (selectedPageTab === 'actual_matching') {
|
|
72
|
+
const actualMatchingPeriodKeys = state.expenseAutomationActualMatchingViewState.matchIdsByPeriod[monthYearPeriodId];
|
|
73
|
+
if (state.expenseAutomationActualMatchingViewState.fetchState !==
|
|
74
|
+
'In-Progress' &&
|
|
75
|
+
(!state.expenseAutomationActualMatchingViewState.hasValidState() ||
|
|
76
|
+
actualMatchingPeriodKeys == null)) {
|
|
77
|
+
fetchActions.push(fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const jeSchedulesPeriodTabKey = getJESchedulePeriodTabKey(selectedPageTab, monthYearPeriodId);
|
|
82
|
+
if (state.expenseAutomationJESchedulesViewState.fetchState !==
|
|
83
|
+
'In-Progress' &&
|
|
84
|
+
(!state.expenseAutomationJESchedulesViewState.hasValidState() ||
|
|
85
|
+
state.expenseAutomationJESchedulesViewState
|
|
86
|
+
.jeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null ||
|
|
87
|
+
state.expenseAutomationJESchedulesViewState
|
|
88
|
+
.failedJeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null)) {
|
|
89
|
+
fetchActions.push(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
|
|
90
|
+
}
|
|
74
91
|
}
|
|
75
92
|
if (state.expenseAutomationReconciliationViewState.fetchState !==
|
|
76
93
|
'In-Progress' &&
|
package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js
CHANGED
|
@@ -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),
|
package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js
CHANGED
|
@@ -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
|
-
|
|
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,7 @@ export function getExpenseAutomationView(state) {
|
|
|
42
43
|
const reconciliation = getExpenseAutomationReconciliationView(state);
|
|
43
44
|
const expenseAutomationTransactionsView = getExpenseAutomationTransactionView(state);
|
|
44
45
|
const jeSchedules = getExpenseAutomationJESchedulesView(state);
|
|
46
|
+
const actualMatching = getExpenseAutomationActualMatchingView(state);
|
|
45
47
|
switch (currentSelectedView) {
|
|
46
48
|
case 'reconciliation':
|
|
47
49
|
currentSelectedViewFetchState = reconciliation.fetchStatus;
|
|
@@ -54,12 +56,23 @@ export function getExpenseAutomationView(state) {
|
|
|
54
56
|
fluxAnalysis.refreshStatus;
|
|
55
57
|
break;
|
|
56
58
|
case 'je_schedules':
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
if (expenseAutomationJESchedulesViewState.uiState.selectedPageTab ===
|
|
60
|
+
'actual_matching') {
|
|
61
|
+
currentSelectedViewFetchState = {
|
|
62
|
+
fetchState: actualMatching.fetchState,
|
|
63
|
+
error: actualMatching.error,
|
|
64
|
+
};
|
|
65
|
+
currentSelectedViewBackgroundRefreshFetchState =
|
|
66
|
+
actualMatching.refreshStatus;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
currentSelectedViewFetchState = {
|
|
70
|
+
fetchState: jeSchedules.fetchState,
|
|
71
|
+
error: jeSchedules.error,
|
|
72
|
+
};
|
|
73
|
+
currentSelectedViewBackgroundRefreshFetchState =
|
|
74
|
+
jeSchedules.refreshStatus;
|
|
75
|
+
}
|
|
63
76
|
break;
|
|
64
77
|
case 'missing_receipts':
|
|
65
78
|
currentSelectedViewFetchState = {
|
|
@@ -91,6 +104,7 @@ export function getExpenseAutomationView(state) {
|
|
|
91
104
|
const fetchStateVariables = [
|
|
92
105
|
expenseAutomationMissingReceiptsViewState,
|
|
93
106
|
expenseAutomationJESchedulesViewState,
|
|
107
|
+
expenseAutomationActualMatchingViewState,
|
|
94
108
|
expenseAutomationTransactionsView,
|
|
95
109
|
expenseAutomationReconciliationViewState,
|
|
96
110
|
];
|
|
@@ -176,6 +190,7 @@ export function getExpenseAutomationView(state) {
|
|
|
176
190
|
]);
|
|
177
191
|
return {
|
|
178
192
|
jeSchedules,
|
|
193
|
+
actualMatching,
|
|
179
194
|
transactionView: expenseAutomationTransactionsView,
|
|
180
195
|
missingReceipts,
|
|
181
196
|
reconciliation,
|
|
@@ -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
|
+
}
|