@zeniai/client-epic-state 5.2.62-beta0MM → 5.2.62-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.
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +4 -2
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +19 -10
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +33 -13
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +3 -2
- package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +4 -30
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +3 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +17 -8
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +4 -1
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +33 -13
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +3 -2
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +2 -2
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.d.ts +1 -1
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +4 -30
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { from } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
3
|
-
import { updateActualMatchingMatches } from '../../../../../entity/actualMatching/actualMatchingReducer';
|
|
3
|
+
import { removeActualMatchingMatch, updateActualMatchingMatches, } from '../../../../../entity/actualMatching/actualMatchingReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
|
|
5
5
|
import { clearAll } from '../../../../../rootActions';
|
|
6
6
|
import { fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess, } from '../../../reducers/actualMatchingViewReducer';
|
|
@@ -32,5 +32,7 @@ export const fetchActualMatchingMatchEpic = (actions$, state$, zeniAPI) => actio
|
|
|
32
32
|
refreshViewInBackground,
|
|
33
33
|
status: createZeniAPIStatus('Unexpected Error', `Fetch actual matching match REST API call errored out ${JSON.stringify(error)}`),
|
|
34
34
|
}),
|
|
35
|
-
])), takeUntil(actions$.pipe(filter(clearAll.match)
|
|
35
|
+
])), takeUntil(actions$.pipe(filter((action) => clearAll.match(action) ||
|
|
36
|
+
(removeActualMatchingMatch.match(action) &&
|
|
37
|
+
action.payload.matchId === matchId)))));
|
|
36
38
|
}));
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { from, of } from 'rxjs';
|
|
2
|
-
import { catchError, exhaustMap, filter, mergeMap, takeUntil } from 'rxjs/operators';
|
|
2
|
+
import { catchError, exhaustMap, filter, groupBy, mergeMap, takeUntil, } from 'rxjs/operators';
|
|
3
3
|
import { getActualMatchingMatchById } from '../../../../../entity/actualMatching/actualMatchingSelector';
|
|
4
4
|
import { openSnackbar } from '../../../../../entity/snackbar/snackbarReducer';
|
|
5
|
-
import { createZeniAPIStatus, isSuccessResponse } from '../../../../../responsePayload';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
|
|
6
6
|
import { clearAll } from '../../../../../rootActions';
|
|
7
7
|
import { toMatchAndReverseResult, } from '../../../payload/actualMatchingPayload';
|
|
8
8
|
import { clearMatchNewModal, fetchActualMatchingMatch, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, } from '../../../reducers/actualMatchingViewReducer';
|
|
9
9
|
import { isMatchAndReverseCompleteStatus, } from '../../../types/actualMatchingViewState';
|
|
10
10
|
import { refreshActualMatchingList } from './refreshActualMatchingList';
|
|
11
11
|
function isMatchFailedStatus(status) {
|
|
12
|
-
return
|
|
12
|
+
return status === 'conflict' || status === 'claim_lost' || status === 'error';
|
|
13
13
|
}
|
|
14
14
|
function matchAndReverseSnackbar(results, vendorName) {
|
|
15
15
|
const reversedCount = results.filter((result) => result.status === 'reversed').length;
|
|
@@ -56,12 +56,15 @@ function matchAndReverseHttpFailSnackbar(vendorName) {
|
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
function matchVendorName(state, matchId) {
|
|
59
|
-
return getActualMatchingMatchById(state.actualMatchingState, matchId)
|
|
59
|
+
return (getActualMatchingMatchById(state.actualMatchingState, matchId)
|
|
60
|
+
?.vendorName ?? '');
|
|
60
61
|
}
|
|
61
62
|
export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(matchAndReverseAccruals.match),
|
|
62
|
-
//
|
|
63
|
-
exhaustMap
|
|
64
|
-
|
|
63
|
+
// Per-match exhaust: a second click on the same match drops while HTTP is in
|
|
64
|
+
// flight. A different match must still run — a global exhaustMap left the
|
|
65
|
+
// other match's reducer In-Progress with no request.
|
|
66
|
+
groupBy((action) => `${action.payload.transactionType.toLowerCase()}:${action.payload.transactionIntegrationId}`), mergeMap((perMatch$) => perMatch$.pipe(exhaustMap((action) => {
|
|
67
|
+
const { transactionId, transactionIntegrationId, transactionType, lineIds, accrualIds, transactionSyncToken, forMatchModal, } = action.payload;
|
|
65
68
|
const body = {
|
|
66
69
|
transaction_id: transactionId,
|
|
67
70
|
transaction_integration_id: transactionIntegrationId,
|
|
@@ -80,7 +83,11 @@ exhaustMap((action) => {
|
|
|
80
83
|
if (isSuccessResponse(response) && response.data != null) {
|
|
81
84
|
const results = response.data.results.map(toMatchAndReverseResult);
|
|
82
85
|
const successActions = [
|
|
83
|
-
matchAndReverseAccrualsSuccess({
|
|
86
|
+
matchAndReverseAccrualsSuccess({
|
|
87
|
+
matchId,
|
|
88
|
+
results,
|
|
89
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
90
|
+
}),
|
|
84
91
|
];
|
|
85
92
|
const occupancyChanged = results.some((result) => isMatchAndReverseCompleteStatus(result.status));
|
|
86
93
|
const allComplete = results.length > 0 &&
|
|
@@ -95,7 +102,7 @@ exhaustMap((action) => {
|
|
|
95
102
|
if (snackbar != null) {
|
|
96
103
|
successActions.push(snackbar);
|
|
97
104
|
}
|
|
98
|
-
if (allComplete) {
|
|
105
|
+
if (allComplete && forMatchModal === true) {
|
|
99
106
|
successActions.push(clearMatchNewModal());
|
|
100
107
|
}
|
|
101
108
|
return from(successActions);
|
|
@@ -103,10 +110,12 @@ exhaustMap((action) => {
|
|
|
103
110
|
return of(matchAndReverseAccrualsFailure({
|
|
104
111
|
status: response.status,
|
|
105
112
|
matchId,
|
|
113
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
106
114
|
}), matchAndReverseHttpFailSnackbar(vendorName));
|
|
107
115
|
}), catchError((error) => of(matchAndReverseAccrualsFailure({
|
|
108
116
|
matchId,
|
|
117
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
109
118
|
status: createZeniAPIStatus('Unexpected Error', 'Match and reverse accruals REST API call errored out' +
|
|
110
119
|
JSON.stringify(error)),
|
|
111
120
|
}), matchAndReverseHttpFailSnackbar(vendorName))), takeUntil(actions$.pipe(filter(clearAll.match))));
|
|
112
|
-
}));
|
|
121
|
+
}))));
|
|
@@ -47,14 +47,22 @@ export const initialState = {
|
|
|
47
47
|
undoReversalStatusByMatchId: {},
|
|
48
48
|
ignoreStatusByMatchId: {},
|
|
49
49
|
confirmStatusByMatchId: {},
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
closeMatchAfterUndoMatchIds: [],
|
|
51
|
+
closeMatchAfterIgnoreMatchIds: [],
|
|
52
52
|
lastMatchResultsByMatchId: {},
|
|
53
53
|
lastUndoResultsByMatchId: {},
|
|
54
54
|
hasValidState() {
|
|
55
55
|
return this.fetchState == 'Completed';
|
|
56
56
|
},
|
|
57
57
|
};
|
|
58
|
+
function enqueueCloseMatchId(ids, matchId) {
|
|
59
|
+
if (!ids.includes(matchId)) {
|
|
60
|
+
ids.push(matchId);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function dropCloseMatchId(ids, matchId) {
|
|
64
|
+
return ids.filter((id) => id !== matchId);
|
|
65
|
+
}
|
|
58
66
|
function pruneLastMatchResultsForUndone(draft, matchId, results) {
|
|
59
67
|
const undoneIds = new Set(results
|
|
60
68
|
.filter((result) => result.status === 'undone')
|
|
@@ -355,11 +363,13 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
355
363
|
fetchState: 'In-Progress',
|
|
356
364
|
error: undefined,
|
|
357
365
|
};
|
|
358
|
-
|
|
366
|
+
if (action.payload.forMatchModal === true) {
|
|
367
|
+
draft.matchModal.confirmStatus = inProgress;
|
|
368
|
+
}
|
|
359
369
|
const matchId = `${action.payload.transactionType.toLowerCase()}:${action.payload.transactionIntegrationId}`;
|
|
360
370
|
draft.confirmStatusByMatchId[matchId] = inProgress;
|
|
361
371
|
},
|
|
362
|
-
prepare(transactionId, transactionIntegrationId, transactionType, lineIds, transactionSyncToken, accrualIds) {
|
|
372
|
+
prepare(transactionId, transactionIntegrationId, transactionType, lineIds, transactionSyncToken, accrualIds, forMatchModal) {
|
|
363
373
|
return {
|
|
364
374
|
payload: {
|
|
365
375
|
accrualIds,
|
|
@@ -368,6 +378,7 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
368
378
|
transactionIntegrationId,
|
|
369
379
|
transactionSyncToken,
|
|
370
380
|
transactionType,
|
|
381
|
+
forMatchModal,
|
|
371
382
|
},
|
|
372
383
|
};
|
|
373
384
|
},
|
|
@@ -376,16 +387,18 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
376
387
|
const { results } = action.payload;
|
|
377
388
|
const allComplete = results.length > 0 &&
|
|
378
389
|
results.every((result) => isMatchAndReverseCompleteStatus(result.status));
|
|
379
|
-
|
|
390
|
+
const confirmStatus = allComplete
|
|
380
391
|
? { fetchState: 'Completed', error: undefined }
|
|
381
392
|
: {
|
|
382
393
|
fetchState: 'Error',
|
|
383
394
|
error: createZeniAPIStatus('Partial match-and-reverse', 'Some accruals were not reversed'),
|
|
384
395
|
};
|
|
385
|
-
|
|
396
|
+
if (action.payload.forMatchModal === true) {
|
|
397
|
+
draft.matchModal.confirmStatus = confirmStatus;
|
|
398
|
+
draft.matchModal.lastBatchResults = results;
|
|
399
|
+
}
|
|
386
400
|
if (action.payload.matchId != null) {
|
|
387
|
-
draft.confirmStatusByMatchId[action.payload.matchId] =
|
|
388
|
-
draft.matchModal.confirmStatus;
|
|
401
|
+
draft.confirmStatusByMatchId[action.payload.matchId] = confirmStatus;
|
|
389
402
|
draft.lastMatchResultsByMatchId[action.payload.matchId] = results;
|
|
390
403
|
pruneLastUndoResultsForMatched(draft, action.payload.matchId, action.payload.results);
|
|
391
404
|
}
|
|
@@ -395,7 +408,9 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
395
408
|
fetchState: 'Error',
|
|
396
409
|
error: action.payload.status,
|
|
397
410
|
};
|
|
398
|
-
|
|
411
|
+
if (action.payload.forMatchModal === true) {
|
|
412
|
+
draft.matchModal.confirmStatus = failed;
|
|
413
|
+
}
|
|
399
414
|
if (action.payload.matchId != null) {
|
|
400
415
|
draft.confirmStatusByMatchId[action.payload.matchId] = failed;
|
|
401
416
|
}
|
|
@@ -420,7 +435,12 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
420
435
|
};
|
|
421
436
|
const allUndone = results.length > 0 &&
|
|
422
437
|
results.every((result) => result.status === 'undone');
|
|
423
|
-
|
|
438
|
+
if (allUndone) {
|
|
439
|
+
enqueueCloseMatchId(draft.closeMatchAfterUndoMatchIds, matchId);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
draft.closeMatchAfterUndoMatchIds = dropCloseMatchId(draft.closeMatchAfterUndoMatchIds, matchId);
|
|
443
|
+
}
|
|
424
444
|
pruneLastMatchResultsForUndone(draft, matchId, results);
|
|
425
445
|
if (allUndone) {
|
|
426
446
|
delete draft.lastUndoResultsByMatchId[matchId];
|
|
@@ -434,7 +454,7 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
434
454
|
},
|
|
435
455
|
},
|
|
436
456
|
ackCloseMatchAfterUndo(draft) {
|
|
437
|
-
draft.
|
|
457
|
+
draft.closeMatchAfterUndoMatchIds.shift();
|
|
438
458
|
},
|
|
439
459
|
ignoreActualMatchingSuggestion: {
|
|
440
460
|
prepare(matchId, reason, note) {
|
|
@@ -453,7 +473,7 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
453
473
|
fetchState: 'Completed',
|
|
454
474
|
error: undefined,
|
|
455
475
|
};
|
|
456
|
-
draft.
|
|
476
|
+
enqueueCloseMatchId(draft.closeMatchAfterIgnoreMatchIds, matchId);
|
|
457
477
|
delete draft.lastMatchResultsByMatchId[matchId];
|
|
458
478
|
delete draft.lastUndoResultsByMatchId[matchId];
|
|
459
479
|
delete draft.detailFetchStateByMatchId[matchId];
|
|
@@ -471,7 +491,7 @@ const expenseAutomationActualMatchingView = createSlice({
|
|
|
471
491
|
};
|
|
472
492
|
},
|
|
473
493
|
ackCloseMatchAfterIgnore(draft) {
|
|
474
|
-
draft.
|
|
494
|
+
draft.closeMatchAfterIgnoreMatchIds.shift();
|
|
475
495
|
},
|
|
476
496
|
undoReversalAccrualsFailure(draft, action) {
|
|
477
497
|
draft.undoReversalStatusByMatchId[action.payload.matchId] = {
|
|
@@ -334,14 +334,15 @@ export function getExpenseAutomationActualMatchingMatchView(state, matchId) {
|
|
|
334
334
|
return selector(state);
|
|
335
335
|
}
|
|
336
336
|
export function getCloseMatchAfterUndo(state) {
|
|
337
|
-
return state.expenseAutomationActualMatchingViewState
|
|
337
|
+
return state.expenseAutomationActualMatchingViewState
|
|
338
|
+
.closeMatchAfterUndoMatchIds[0];
|
|
338
339
|
}
|
|
339
340
|
export function getCloseMatchAfterUndoMatchId(state) {
|
|
340
341
|
return getCloseMatchAfterUndo(state);
|
|
341
342
|
}
|
|
342
343
|
export function getCloseMatchAfterIgnoreMatchId(state) {
|
|
343
344
|
return state.expenseAutomationActualMatchingViewState
|
|
344
|
-
.
|
|
345
|
+
.closeMatchAfterIgnoreMatchIds[0];
|
|
345
346
|
}
|
|
346
347
|
export function getActualMatchingMatchModalConfirmStatus(state, matchId) {
|
|
347
348
|
if (matchId != null && matchId !== '') {
|
|
@@ -625,7 +625,7 @@ export const getDueDate = (billStageCode, dueDate, invoiceDate, bookCloseDate) =
|
|
|
625
625
|
}
|
|
626
626
|
};
|
|
627
627
|
export const getWithdrawFrom = (state, fromAccountId, fromAccountType, companyId, lastSelectedFromAccount) => {
|
|
628
|
-
const { paymentAccountState, depositAccountState,
|
|
628
|
+
const { paymentAccountState, depositAccountState, paymentAccountListState } = state;
|
|
629
629
|
if (fromAccountId != null) {
|
|
630
630
|
const withdrawFromAsDepositAcc = getDepositAccountByDepositAccountId(depositAccountState, fromAccountId);
|
|
631
631
|
const withdrawFromAsPaymentAcc = getPaymentAccountByPaymentAccountId(paymentAccountState, fromAccountId);
|
|
@@ -639,41 +639,15 @@ export const getWithdrawFrom = (state, fromAccountId, fromAccountType, companyId
|
|
|
639
639
|
}
|
|
640
640
|
}
|
|
641
641
|
else {
|
|
642
|
-
return getDefaultWithdrawFromAccount(state,
|
|
642
|
+
return getDefaultWithdrawFromAccount(state, companyId ?? '', lastSelectedFromAccount);
|
|
643
643
|
}
|
|
644
644
|
return undefined;
|
|
645
645
|
};
|
|
646
|
-
export const getDefaultWithdrawFromAccount = (state,
|
|
646
|
+
export const getDefaultWithdrawFromAccount = (state, companyId, lastSelectedFromAccount) => {
|
|
647
647
|
const { depositAccountState, paymentAccountState, paymentAccountListState } = state;
|
|
648
648
|
const companyView = getCompanyView(state, companyId, []);
|
|
649
649
|
const primaryAccount = companyView?.company.company.companyBillPayInfo.primaryFundingAccount;
|
|
650
|
-
|
|
651
|
-
// User paying bill for first time or previously paid with external account
|
|
652
|
-
if (lastSelectedFromAccount == null ||
|
|
653
|
-
lastSelectedFromAccount?.accountType === 'paymentAccount') {
|
|
654
|
-
if (depositAccounts.length === 0) {
|
|
655
|
-
defaultAccount = primaryAccount;
|
|
656
|
-
}
|
|
657
|
-
else {
|
|
658
|
-
if (primaryAccount?.accountType === 'depositAccount') {
|
|
659
|
-
defaultAccount = primaryAccount;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
else {
|
|
664
|
-
// User paid with Zeni account previously
|
|
665
|
-
if (depositAccounts.length === 1) {
|
|
666
|
-
defaultAccount = lastSelectedFromAccount;
|
|
667
|
-
}
|
|
668
|
-
else {
|
|
669
|
-
if (primaryAccount?.accountType === 'depositAccount') {
|
|
670
|
-
defaultAccount = primaryAccount;
|
|
671
|
-
}
|
|
672
|
-
else {
|
|
673
|
-
defaultAccount = lastSelectedFromAccount;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
}
|
|
650
|
+
const defaultAccount = primaryAccount ?? lastSelectedFromAccount;
|
|
677
651
|
if (defaultAccount != null) {
|
|
678
652
|
const defaultAccAsDepositAcc = getDepositAccountByDepositAccountId(depositAccountState, defaultAccount?.accountId);
|
|
679
653
|
const defaultAccAsPaymentAcc = getPaymentAccountByPaymentAccountId(paymentAccountState, defaultAccount?.accountId);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { ActualMatchingMatchPayload } from '../../../../../entity/actualMatching/actualMatchingPayload';
|
|
4
|
-
import { updateActualMatchingMatches } from '../../../../../entity/actualMatching/actualMatchingReducer';
|
|
4
|
+
import { removeActualMatchingMatch, updateActualMatchingMatches } from '../../../../../entity/actualMatching/actualMatchingReducer';
|
|
5
5
|
import { ZeniAPIResponse } from '../../../../../responsePayload';
|
|
6
6
|
import { clearAll } from '../../../../../rootActions';
|
|
7
7
|
import { RootState } from '../../../../../rootStateTypes';
|
|
8
8
|
import { ZeniAPI } from '../../../../../zeniAPI';
|
|
9
9
|
import { fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess } from '../../../reducers/actualMatchingViewReducer';
|
|
10
10
|
export type ActualMatchingMatchResponse = ZeniAPIResponse<ActualMatchingMatchPayload>;
|
|
11
|
-
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof fetchActualMatchingMatch> | ReturnType<typeof fetchActualMatchingMatchFailure> | ReturnType<typeof fetchActualMatchingMatchSuccess> | ReturnType<typeof updateActualMatchingMatches>;
|
|
11
|
+
export type ActionType = ReturnType<typeof clearAll> | ReturnType<typeof fetchActualMatchingMatch> | ReturnType<typeof fetchActualMatchingMatchFailure> | ReturnType<typeof fetchActualMatchingMatchSuccess> | ReturnType<typeof removeActualMatchingMatch> | ReturnType<typeof updateActualMatchingMatches>;
|
|
12
12
|
export declare const fetchActualMatchingMatchEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
|
|
@@ -35,6 +35,8 @@ const fetchActualMatchingMatchEpic = (actions$, state$, zeniAPI) => actions$.pip
|
|
|
35
35
|
refreshViewInBackground,
|
|
36
36
|
status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', `Fetch actual matching match REST API call errored out ${JSON.stringify(error)}`),
|
|
37
37
|
}),
|
|
38
|
-
])), (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match)
|
|
38
|
+
])), (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)((action) => rootActions_1.clearAll.match(action) ||
|
|
39
|
+
(actualMatchingReducer_1.removeActualMatchingMatch.match(action) &&
|
|
40
|
+
action.payload.matchId === matchId)))));
|
|
39
41
|
}));
|
|
40
42
|
exports.fetchActualMatchingMatchEpic = fetchActualMatchingMatchEpic;
|
|
@@ -12,7 +12,7 @@ const actualMatchingViewReducer_1 = require("../../../reducers/actualMatchingVie
|
|
|
12
12
|
const actualMatchingViewState_1 = require("../../../types/actualMatchingViewState");
|
|
13
13
|
const refreshActualMatchingList_1 = require("./refreshActualMatchingList");
|
|
14
14
|
function isMatchFailedStatus(status) {
|
|
15
|
-
return
|
|
15
|
+
return status === 'conflict' || status === 'claim_lost' || status === 'error';
|
|
16
16
|
}
|
|
17
17
|
function matchAndReverseSnackbar(results, vendorName) {
|
|
18
18
|
const reversedCount = results.filter((result) => result.status === 'reversed').length;
|
|
@@ -59,12 +59,15 @@ function matchAndReverseHttpFailSnackbar(vendorName) {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
function matchVendorName(state, matchId) {
|
|
62
|
-
return (0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchId)
|
|
62
|
+
return ((0, actualMatchingSelector_1.getActualMatchingMatchById)(state.actualMatchingState, matchId)
|
|
63
|
+
?.vendorName ?? '');
|
|
63
64
|
}
|
|
64
65
|
const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(actualMatchingViewReducer_1.matchAndReverseAccruals.match),
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
// Per-match exhaust: a second click on the same match drops while HTTP is in
|
|
67
|
+
// flight. A different match must still run — a global exhaustMap left the
|
|
68
|
+
// other match's reducer In-Progress with no request.
|
|
69
|
+
(0, operators_1.groupBy)((action) => `${action.payload.transactionType.toLowerCase()}:${action.payload.transactionIntegrationId}`), (0, operators_1.mergeMap)((perMatch$) => perMatch$.pipe((0, operators_1.exhaustMap)((action) => {
|
|
70
|
+
const { transactionId, transactionIntegrationId, transactionType, lineIds, accrualIds, transactionSyncToken, forMatchModal, } = action.payload;
|
|
68
71
|
const body = {
|
|
69
72
|
transaction_id: transactionId,
|
|
70
73
|
transaction_integration_id: transactionIntegrationId,
|
|
@@ -83,7 +86,11 @@ const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
83
86
|
if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
|
|
84
87
|
const results = response.data.results.map(actualMatchingPayload_1.toMatchAndReverseResult);
|
|
85
88
|
const successActions = [
|
|
86
|
-
(0, actualMatchingViewReducer_1.matchAndReverseAccrualsSuccess)({
|
|
89
|
+
(0, actualMatchingViewReducer_1.matchAndReverseAccrualsSuccess)({
|
|
90
|
+
matchId,
|
|
91
|
+
results,
|
|
92
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
93
|
+
}),
|
|
87
94
|
];
|
|
88
95
|
const occupancyChanged = results.some((result) => (0, actualMatchingViewState_1.isMatchAndReverseCompleteStatus)(result.status));
|
|
89
96
|
const allComplete = results.length > 0 &&
|
|
@@ -98,7 +105,7 @@ const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
98
105
|
if (snackbar != null) {
|
|
99
106
|
successActions.push(snackbar);
|
|
100
107
|
}
|
|
101
|
-
if (allComplete) {
|
|
108
|
+
if (allComplete && forMatchModal === true) {
|
|
102
109
|
successActions.push((0, actualMatchingViewReducer_1.clearMatchNewModal)());
|
|
103
110
|
}
|
|
104
111
|
return (0, rxjs_1.from)(successActions);
|
|
@@ -106,11 +113,13 @@ const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe
|
|
|
106
113
|
return (0, rxjs_1.of)((0, actualMatchingViewReducer_1.matchAndReverseAccrualsFailure)({
|
|
107
114
|
status: response.status,
|
|
108
115
|
matchId,
|
|
116
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
109
117
|
}), matchAndReverseHttpFailSnackbar(vendorName));
|
|
110
118
|
}), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, actualMatchingViewReducer_1.matchAndReverseAccrualsFailure)({
|
|
111
119
|
matchId,
|
|
120
|
+
...(forMatchModal === true ? { forMatchModal: true } : {}),
|
|
112
121
|
status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Match and reverse accruals REST API call errored out' +
|
|
113
122
|
JSON.stringify(error)),
|
|
114
123
|
}), matchAndReverseHttpFailSnackbar(vendorName))), (0, operators_1.takeUntil)(actions$.pipe((0, operators_1.filter)(rootActions_1.clearAll.match))));
|
|
115
|
-
}));
|
|
124
|
+
}))));
|
|
116
125
|
exports.matchAndReverseAccrualsEpic = matchAndReverseAccrualsEpic;
|
|
@@ -40,18 +40,21 @@ export declare const ackCloseMatchAfterIgnore: import("@reduxjs/toolkit").Action
|
|
|
40
40
|
status: ZeniAPIStatus;
|
|
41
41
|
}, "expenseAutomationActualMatchingView/ignoreActualMatchingSuggestionFailure">, ignoreActualMatchingSuggestionSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
42
42
|
matchId: ActualMatchingMatchId;
|
|
43
|
-
}, "expenseAutomationActualMatchingView/ignoreActualMatchingSuggestionSuccess">, matchAndReverseAccruals: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: string, transactionIntegrationId: string, transactionType: string, lineIds: string[], transactionSyncToken: string, accrualIds: string[]], {
|
|
43
|
+
}, "expenseAutomationActualMatchingView/ignoreActualMatchingSuggestionSuccess">, matchAndReverseAccruals: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: string, transactionIntegrationId: string, transactionType: string, lineIds: string[], transactionSyncToken: string, accrualIds: string[], forMatchModal?: boolean | undefined], {
|
|
44
44
|
accrualIds: string[];
|
|
45
45
|
lineIds: string[];
|
|
46
46
|
transactionId: string;
|
|
47
47
|
transactionIntegrationId: string;
|
|
48
48
|
transactionSyncToken: string;
|
|
49
49
|
transactionType: string;
|
|
50
|
+
forMatchModal: boolean | undefined;
|
|
50
51
|
}, "expenseAutomationActualMatchingView/matchAndReverseAccruals", never, never>, matchAndReverseAccrualsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
51
52
|
status: ZeniAPIStatus;
|
|
53
|
+
forMatchModal?: boolean;
|
|
52
54
|
matchId?: ActualMatchingMatchId;
|
|
53
55
|
}, "expenseAutomationActualMatchingView/matchAndReverseAccrualsFailure">, matchAndReverseAccrualsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
54
56
|
results: MatchAndReverseResult[];
|
|
57
|
+
forMatchModal?: boolean;
|
|
55
58
|
matchId?: ActualMatchingMatchId;
|
|
56
59
|
}, "expenseAutomationActualMatchingView/matchAndReverseAccrualsSuccess">, openMatchNewModal: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationActualMatchingView/openMatchNewModal">, searchMatchAccruals: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[query: string, pageToken?: string | null | undefined], {
|
|
57
60
|
query: string;
|
|
@@ -51,14 +51,22 @@ exports.initialState = {
|
|
|
51
51
|
undoReversalStatusByMatchId: {},
|
|
52
52
|
ignoreStatusByMatchId: {},
|
|
53
53
|
confirmStatusByMatchId: {},
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
closeMatchAfterUndoMatchIds: [],
|
|
55
|
+
closeMatchAfterIgnoreMatchIds: [],
|
|
56
56
|
lastMatchResultsByMatchId: {},
|
|
57
57
|
lastUndoResultsByMatchId: {},
|
|
58
58
|
hasValidState() {
|
|
59
59
|
return this.fetchState == 'Completed';
|
|
60
60
|
},
|
|
61
61
|
};
|
|
62
|
+
function enqueueCloseMatchId(ids, matchId) {
|
|
63
|
+
if (!ids.includes(matchId)) {
|
|
64
|
+
ids.push(matchId);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function dropCloseMatchId(ids, matchId) {
|
|
68
|
+
return ids.filter((id) => id !== matchId);
|
|
69
|
+
}
|
|
62
70
|
function pruneLastMatchResultsForUndone(draft, matchId, results) {
|
|
63
71
|
const undoneIds = new Set(results
|
|
64
72
|
.filter((result) => result.status === 'undone')
|
|
@@ -359,11 +367,13 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
359
367
|
fetchState: 'In-Progress',
|
|
360
368
|
error: undefined,
|
|
361
369
|
};
|
|
362
|
-
|
|
370
|
+
if (action.payload.forMatchModal === true) {
|
|
371
|
+
draft.matchModal.confirmStatus = inProgress;
|
|
372
|
+
}
|
|
363
373
|
const matchId = `${action.payload.transactionType.toLowerCase()}:${action.payload.transactionIntegrationId}`;
|
|
364
374
|
draft.confirmStatusByMatchId[matchId] = inProgress;
|
|
365
375
|
},
|
|
366
|
-
prepare(transactionId, transactionIntegrationId, transactionType, lineIds, transactionSyncToken, accrualIds) {
|
|
376
|
+
prepare(transactionId, transactionIntegrationId, transactionType, lineIds, transactionSyncToken, accrualIds, forMatchModal) {
|
|
367
377
|
return {
|
|
368
378
|
payload: {
|
|
369
379
|
accrualIds,
|
|
@@ -372,6 +382,7 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
372
382
|
transactionIntegrationId,
|
|
373
383
|
transactionSyncToken,
|
|
374
384
|
transactionType,
|
|
385
|
+
forMatchModal,
|
|
375
386
|
},
|
|
376
387
|
};
|
|
377
388
|
},
|
|
@@ -380,16 +391,18 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
380
391
|
const { results } = action.payload;
|
|
381
392
|
const allComplete = results.length > 0 &&
|
|
382
393
|
results.every((result) => (0, actualMatchingViewState_1.isMatchAndReverseCompleteStatus)(result.status));
|
|
383
|
-
|
|
394
|
+
const confirmStatus = allComplete
|
|
384
395
|
? { fetchState: 'Completed', error: undefined }
|
|
385
396
|
: {
|
|
386
397
|
fetchState: 'Error',
|
|
387
398
|
error: (0, responsePayload_1.createZeniAPIStatus)('Partial match-and-reverse', 'Some accruals were not reversed'),
|
|
388
399
|
};
|
|
389
|
-
|
|
400
|
+
if (action.payload.forMatchModal === true) {
|
|
401
|
+
draft.matchModal.confirmStatus = confirmStatus;
|
|
402
|
+
draft.matchModal.lastBatchResults = results;
|
|
403
|
+
}
|
|
390
404
|
if (action.payload.matchId != null) {
|
|
391
|
-
draft.confirmStatusByMatchId[action.payload.matchId] =
|
|
392
|
-
draft.matchModal.confirmStatus;
|
|
405
|
+
draft.confirmStatusByMatchId[action.payload.matchId] = confirmStatus;
|
|
393
406
|
draft.lastMatchResultsByMatchId[action.payload.matchId] = results;
|
|
394
407
|
pruneLastUndoResultsForMatched(draft, action.payload.matchId, action.payload.results);
|
|
395
408
|
}
|
|
@@ -399,7 +412,9 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
399
412
|
fetchState: 'Error',
|
|
400
413
|
error: action.payload.status,
|
|
401
414
|
};
|
|
402
|
-
|
|
415
|
+
if (action.payload.forMatchModal === true) {
|
|
416
|
+
draft.matchModal.confirmStatus = failed;
|
|
417
|
+
}
|
|
403
418
|
if (action.payload.matchId != null) {
|
|
404
419
|
draft.confirmStatusByMatchId[action.payload.matchId] = failed;
|
|
405
420
|
}
|
|
@@ -424,7 +439,12 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
424
439
|
};
|
|
425
440
|
const allUndone = results.length > 0 &&
|
|
426
441
|
results.every((result) => result.status === 'undone');
|
|
427
|
-
|
|
442
|
+
if (allUndone) {
|
|
443
|
+
enqueueCloseMatchId(draft.closeMatchAfterUndoMatchIds, matchId);
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
draft.closeMatchAfterUndoMatchIds = dropCloseMatchId(draft.closeMatchAfterUndoMatchIds, matchId);
|
|
447
|
+
}
|
|
428
448
|
pruneLastMatchResultsForUndone(draft, matchId, results);
|
|
429
449
|
if (allUndone) {
|
|
430
450
|
delete draft.lastUndoResultsByMatchId[matchId];
|
|
@@ -438,7 +458,7 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
438
458
|
},
|
|
439
459
|
},
|
|
440
460
|
ackCloseMatchAfterUndo(draft) {
|
|
441
|
-
draft.
|
|
461
|
+
draft.closeMatchAfterUndoMatchIds.shift();
|
|
442
462
|
},
|
|
443
463
|
ignoreActualMatchingSuggestion: {
|
|
444
464
|
prepare(matchId, reason, note) {
|
|
@@ -457,7 +477,7 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
457
477
|
fetchState: 'Completed',
|
|
458
478
|
error: undefined,
|
|
459
479
|
};
|
|
460
|
-
draft.
|
|
480
|
+
enqueueCloseMatchId(draft.closeMatchAfterIgnoreMatchIds, matchId);
|
|
461
481
|
delete draft.lastMatchResultsByMatchId[matchId];
|
|
462
482
|
delete draft.lastUndoResultsByMatchId[matchId];
|
|
463
483
|
delete draft.detailFetchStateByMatchId[matchId];
|
|
@@ -475,7 +495,7 @@ const expenseAutomationActualMatchingView = (0, toolkit_1.createSlice)({
|
|
|
475
495
|
};
|
|
476
496
|
},
|
|
477
497
|
ackCloseMatchAfterIgnore(draft) {
|
|
478
|
-
draft.
|
|
498
|
+
draft.closeMatchAfterIgnoreMatchIds.shift();
|
|
479
499
|
},
|
|
480
500
|
undoReversalAccrualsFailure(draft, action) {
|
|
481
501
|
draft.undoReversalStatusByMatchId[action.payload.matchId] = {
|
|
@@ -356,14 +356,15 @@ function getExpenseAutomationActualMatchingMatchView(state, matchId) {
|
|
|
356
356
|
return selector(state);
|
|
357
357
|
}
|
|
358
358
|
function getCloseMatchAfterUndo(state) {
|
|
359
|
-
return state.expenseAutomationActualMatchingViewState
|
|
359
|
+
return state.expenseAutomationActualMatchingViewState
|
|
360
|
+
.closeMatchAfterUndoMatchIds[0];
|
|
360
361
|
}
|
|
361
362
|
function getCloseMatchAfterUndoMatchId(state) {
|
|
362
363
|
return getCloseMatchAfterUndo(state);
|
|
363
364
|
}
|
|
364
365
|
function getCloseMatchAfterIgnoreMatchId(state) {
|
|
365
366
|
return state.expenseAutomationActualMatchingViewState
|
|
366
|
-
.
|
|
367
|
+
.closeMatchAfterIgnoreMatchIds[0];
|
|
367
368
|
}
|
|
368
369
|
function getActualMatchingMatchModalConfirmStatus(state, matchId) {
|
|
369
370
|
if (matchId != null && matchId !== '') {
|
|
@@ -106,6 +106,8 @@ export interface ActualMatchingMatchModalState {
|
|
|
106
106
|
}
|
|
107
107
|
export declare function actualMatchingTransactionLineKey(transactionType: string, transactionIntegrationId: string, lineId: string): string;
|
|
108
108
|
export interface ActualMatchingViewState extends FetchedState {
|
|
109
|
+
closeMatchAfterIgnoreMatchIds: ActualMatchingMatchId[];
|
|
110
|
+
closeMatchAfterUndoMatchIds: ActualMatchingMatchId[];
|
|
109
111
|
confirmStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
110
112
|
detailFetchStateByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
111
113
|
detailRefreshStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
@@ -117,6 +119,4 @@ export interface ActualMatchingViewState extends FetchedState {
|
|
|
117
119
|
refreshStatus: FetchStateAndError;
|
|
118
120
|
uiState: ActualMatchingViewUIState;
|
|
119
121
|
undoReversalStatusByMatchId: Record<ActualMatchingMatchId, FetchStateAndError>;
|
|
120
|
-
closeMatchAfterIgnoreMatchId?: ActualMatchingMatchId;
|
|
121
|
-
closeMatchAfterUndoMatchId?: ActualMatchingMatchId;
|
|
122
122
|
}
|
|
@@ -141,7 +141,7 @@ export declare const getWithdrawFrom: (state: RootState, fromAccountId?: ID, fro
|
|
|
141
141
|
accountId: ID;
|
|
142
142
|
accountType: AccountTypeSubConfigCodeKeyType;
|
|
143
143
|
}) => FundingAccount | undefined;
|
|
144
|
-
export declare const getDefaultWithdrawFromAccount: (state: RootState,
|
|
144
|
+
export declare const getDefaultWithdrawFromAccount: (state: RootState, companyId: ID, lastSelectedFromAccount?: {
|
|
145
145
|
accountId: ID;
|
|
146
146
|
accountType: AccountTypeSubConfigCodeKeyType;
|
|
147
147
|
}) => FundingAccount | undefined;
|
|
@@ -640,7 +640,7 @@ const getDueDate = (billStageCode, dueDate, invoiceDate, bookCloseDate) => {
|
|
|
640
640
|
};
|
|
641
641
|
exports.getDueDate = getDueDate;
|
|
642
642
|
const getWithdrawFrom = (state, fromAccountId, fromAccountType, companyId, lastSelectedFromAccount) => {
|
|
643
|
-
const { paymentAccountState, depositAccountState,
|
|
643
|
+
const { paymentAccountState, depositAccountState, paymentAccountListState } = state;
|
|
644
644
|
if (fromAccountId != null) {
|
|
645
645
|
const withdrawFromAsDepositAcc = (0, depositAccountSelector_1.getDepositAccountByDepositAccountId)(depositAccountState, fromAccountId);
|
|
646
646
|
const withdrawFromAsPaymentAcc = (0, paymentAccountSelector_1.getPaymentAccountByPaymentAccountId)(paymentAccountState, fromAccountId);
|
|
@@ -654,42 +654,16 @@ const getWithdrawFrom = (state, fromAccountId, fromAccountType, companyId, lastS
|
|
|
654
654
|
}
|
|
655
655
|
}
|
|
656
656
|
else {
|
|
657
|
-
return (0, exports.getDefaultWithdrawFromAccount)(state,
|
|
657
|
+
return (0, exports.getDefaultWithdrawFromAccount)(state, companyId ?? '', lastSelectedFromAccount);
|
|
658
658
|
}
|
|
659
659
|
return undefined;
|
|
660
660
|
};
|
|
661
661
|
exports.getWithdrawFrom = getWithdrawFrom;
|
|
662
|
-
const getDefaultWithdrawFromAccount = (state,
|
|
662
|
+
const getDefaultWithdrawFromAccount = (state, companyId, lastSelectedFromAccount) => {
|
|
663
663
|
const { depositAccountState, paymentAccountState, paymentAccountListState } = state;
|
|
664
664
|
const companyView = (0, getCompanyView_1.getCompanyView)(state, companyId, []);
|
|
665
665
|
const primaryAccount = companyView?.company.company.companyBillPayInfo.primaryFundingAccount;
|
|
666
|
-
|
|
667
|
-
// User paying bill for first time or previously paid with external account
|
|
668
|
-
if (lastSelectedFromAccount == null ||
|
|
669
|
-
lastSelectedFromAccount?.accountType === 'paymentAccount') {
|
|
670
|
-
if (depositAccounts.length === 0) {
|
|
671
|
-
defaultAccount = primaryAccount;
|
|
672
|
-
}
|
|
673
|
-
else {
|
|
674
|
-
if (primaryAccount?.accountType === 'depositAccount') {
|
|
675
|
-
defaultAccount = primaryAccount;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
// User paid with Zeni account previously
|
|
681
|
-
if (depositAccounts.length === 1) {
|
|
682
|
-
defaultAccount = lastSelectedFromAccount;
|
|
683
|
-
}
|
|
684
|
-
else {
|
|
685
|
-
if (primaryAccount?.accountType === 'depositAccount') {
|
|
686
|
-
defaultAccount = primaryAccount;
|
|
687
|
-
}
|
|
688
|
-
else {
|
|
689
|
-
defaultAccount = lastSelectedFromAccount;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
}
|
|
666
|
+
const defaultAccount = primaryAccount ?? lastSelectedFromAccount;
|
|
693
667
|
if (defaultAccount != null) {
|
|
694
668
|
const defaultAccAsDepositAcc = (0, depositAccountSelector_1.getDepositAccountByDepositAccountId)(depositAccountState, defaultAccount?.accountId);
|
|
695
669
|
const defaultAccAsPaymentAcc = (0, paymentAccountSelector_1.getPaymentAccountByPaymentAccountId)(paymentAccountState, defaultAccount?.accountId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.2.62-
|
|
3
|
+
"version": "5.2.62-beta1MM",
|
|
4
4
|
"description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/esm/index.js",
|