@zeniai/client-epic-state 4.19.37-betaAS2 → 4.19.37-betaVR10
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/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/epic.d.ts +10 -1
- package/lib/epic.js +10 -1
- package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/esm/epic.js +10 -1
- package/lib/esm/index.js +8 -6
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +24 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +49 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +31 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +41 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +57 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +31 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +39 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +27 -0
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +44 -0
- package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +96 -1
- package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +280 -1
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +134 -1
- package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.js +1 -10
- package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +2 -4
- package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +2 -5
- package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.js +1 -10
- package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +2 -4
- package/lib/esm/zeniAPI.js +41 -3
- package/lib/index.d.ts +11 -9
- package/lib/index.js +60 -32
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +15 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +28 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +7 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +53 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +35 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +7 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +45 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +61 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +35 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.d.ts +9 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +44 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.d.ts +6 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +31 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +8 -0
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +49 -0
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +98 -0
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +102 -0
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +53 -3
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +281 -2
- package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +64 -1
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.d.ts +1 -1
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +133 -0
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +106 -0
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.js +2 -11
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +2 -4
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelectorTypes.d.ts +0 -2
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewState.d.ts +0 -1
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.d.ts +0 -1
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +2 -5
- package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonState.d.ts +0 -2
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.d.ts +1 -1
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.js +2 -11
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +2 -4
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelectorTypes.d.ts +0 -2
- package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewState.d.ts +0 -1
- package/lib/zeniAPI.d.ts +9 -0
- package/lib/zeniAPI.js +40 -2
- package/package.json +2 -2
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { from } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
6
|
+
export const confirmBulkUploadMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(confirmBulkUploadMatch.match), mergeMap((action) => {
|
|
7
|
+
const { batchId, attachmentId, transactionId, transactionType, fileName } = action.payload;
|
|
8
|
+
return zeniAPI
|
|
9
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/manual-match`, {
|
|
10
|
+
attachment_id: attachmentId,
|
|
11
|
+
transaction_id: transactionId,
|
|
12
|
+
transaction_type: transactionType,
|
|
13
|
+
file_name: fileName,
|
|
14
|
+
})
|
|
15
|
+
.pipe(mergeMap((response) => {
|
|
16
|
+
if (isSuccessResponse(response)) {
|
|
17
|
+
return from([
|
|
18
|
+
confirmBulkUploadMatchSuccess({
|
|
19
|
+
batchId,
|
|
20
|
+
attachmentId,
|
|
21
|
+
transactionId,
|
|
22
|
+
}),
|
|
23
|
+
openSnackbar({
|
|
24
|
+
messageSection: 'receipt_match',
|
|
25
|
+
messageText: 'success',
|
|
26
|
+
type: 'success',
|
|
27
|
+
}),
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
return from([
|
|
31
|
+
confirmBulkUploadMatchFailure({ error: response.status }),
|
|
32
|
+
openSnackbar({
|
|
33
|
+
messageSection: 'receipt_match',
|
|
34
|
+
messageText: 'failed',
|
|
35
|
+
type: 'error',
|
|
36
|
+
}),
|
|
37
|
+
]);
|
|
38
|
+
}), catchError((error) => from([
|
|
39
|
+
confirmBulkUploadMatchFailure({
|
|
40
|
+
error: createZeniAPIStatus('Unexpected Error', 'Confirm bulk upload match errored out: ' +
|
|
41
|
+
JSON.stringify(error)),
|
|
42
|
+
}),
|
|
43
|
+
openSnackbar({
|
|
44
|
+
messageSection: 'receipt_match',
|
|
45
|
+
messageText: 'failed',
|
|
46
|
+
type: 'error',
|
|
47
|
+
}),
|
|
48
|
+
])));
|
|
49
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { extractTransactionPayloadsFromBatchFiles, toBatchDetails, } from '../../payload/missingReceiptsPayload';
|
|
6
|
+
import { fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, } from '../../reducers/missingReceiptsViewReducer';
|
|
7
|
+
export const fetchBulkUploadBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatchDetails.match), mergeMap(() => {
|
|
8
|
+
const { currentBatchId } = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
|
|
9
|
+
if (currentBatchId == null) {
|
|
10
|
+
return of(fetchBulkUploadBatchDetailsFailure({
|
|
11
|
+
error: createZeniAPIStatus('Unexpected Error', 'No current batch ID available'),
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
return zeniAPI
|
|
15
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/batches/${currentBatchId}`)
|
|
16
|
+
.pipe(mergeMap((response) => {
|
|
17
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
18
|
+
const actions = [];
|
|
19
|
+
const transactionPayloads = extractTransactionPayloadsFromBatchFiles(response.data.files);
|
|
20
|
+
if (transactionPayloads.length > 0) {
|
|
21
|
+
actions.push(updateTransactions(transactionPayloads, (value) => value.transaction_id));
|
|
22
|
+
}
|
|
23
|
+
actions.push(fetchBulkUploadBatchDetailsSuccess(toBatchDetails(response.data, zeniAPI.apiEndPoints.fileMicroServiceBaseUrl)));
|
|
24
|
+
actions.push(fetchBulkUploadBatches(true));
|
|
25
|
+
return from(actions);
|
|
26
|
+
}
|
|
27
|
+
return of(fetchBulkUploadBatchDetailsFailure({ error: response.status }));
|
|
28
|
+
}), catchError((error) => of(fetchBulkUploadBatchDetailsFailure({
|
|
29
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch batch details errored out: ' + JSON.stringify(error)),
|
|
30
|
+
}))));
|
|
31
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
|
+
import { toBatchListItem, } from '../../payload/missingReceiptsPayload';
|
|
7
|
+
import { fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
8
|
+
export const fetchBulkUploadBatchesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatches.match), switchMap((action) => {
|
|
9
|
+
const { cacheOverride } = action.payload;
|
|
10
|
+
const state = state$.value;
|
|
11
|
+
const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
|
|
12
|
+
const currentTenant = getCurrentTenant(state);
|
|
13
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
14
|
+
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
15
|
+
const existingBatches = bulkUpload.batchListByPeriod[periodId] ?? [];
|
|
16
|
+
if (cacheOverride !== true && existingBatches.length > 0) {
|
|
17
|
+
return of(fetchBulkUploadBatchesSuccess({
|
|
18
|
+
batchList: existingBatches,
|
|
19
|
+
selectedPeriod,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
const period = convertToPeriod(selectedPeriod);
|
|
23
|
+
return zeniAPI
|
|
24
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/batches?start_date=${period.start}&end_date=${period.end}`)
|
|
25
|
+
.pipe(mergeMap((response) => {
|
|
26
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
27
|
+
return of(fetchBulkUploadBatchesSuccess({
|
|
28
|
+
batchList: response.data.batches.map(toBatchListItem),
|
|
29
|
+
selectedPeriod,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
return of(fetchBulkUploadBatchesFailure({
|
|
33
|
+
error: response.status,
|
|
34
|
+
selectedPeriod,
|
|
35
|
+
}));
|
|
36
|
+
}), catchError((error) => of(fetchBulkUploadBatchesFailure({
|
|
37
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch bulk upload batches errored out: ' +
|
|
38
|
+
JSON.stringify(error)),
|
|
39
|
+
selectedPeriod,
|
|
40
|
+
}))));
|
|
41
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
6
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
7
|
+
import { fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
8
|
+
export const fetchCompletedTransactionsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchCompletedTransactions.match), switchMap((action) => {
|
|
9
|
+
const state = state$.value;
|
|
10
|
+
const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
|
|
11
|
+
const currentTenant = getCurrentTenant(state);
|
|
12
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
13
|
+
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
14
|
+
const isInitialLoad = action.payload.pageToken == null;
|
|
15
|
+
const existingData = bulkUpload.completedTransactionsByPeriod[periodId];
|
|
16
|
+
if (isInitialLoad && existingData != null && existingData.transactionIds.length > 0) {
|
|
17
|
+
return from([]);
|
|
18
|
+
}
|
|
19
|
+
const period = convertToPeriod(selectedPeriod);
|
|
20
|
+
const queryPayload = {
|
|
21
|
+
start_date: period.start,
|
|
22
|
+
end_date: period.end,
|
|
23
|
+
sort_by: bulkUpload.sortKey,
|
|
24
|
+
sort_order: bulkUpload.sortOrder === 'ascending' ? 'asc' : 'desc',
|
|
25
|
+
page_token: action.payload.pageToken ?? null,
|
|
26
|
+
page_size: 25,
|
|
27
|
+
};
|
|
28
|
+
if (bulkUpload.completedSubTab !== 'all') {
|
|
29
|
+
queryPayload.match_type = bulkUpload.completedSubTab;
|
|
30
|
+
}
|
|
31
|
+
const encodedQuery = encodeURIComponent(JSON.stringify(queryPayload));
|
|
32
|
+
return zeniAPI
|
|
33
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipt-agent/transactions/completed?query=${encodedQuery}`)
|
|
34
|
+
.pipe(mergeMap((response) => {
|
|
35
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
36
|
+
const transactionIds = response.data.transactions.map((t) => t.transaction_id);
|
|
37
|
+
const updateActions = [];
|
|
38
|
+
updateActions.push(updateTransactions(response.data.transactions, (value) => value.transaction_id));
|
|
39
|
+
updateActions.push(fetchCompletedTransactionsSuccess({
|
|
40
|
+
isInitialLoad,
|
|
41
|
+
transactionIds,
|
|
42
|
+
nextPageToken: response.data.next_page_token,
|
|
43
|
+
totalCount: response.data.total_count,
|
|
44
|
+
selectedPeriod,
|
|
45
|
+
}));
|
|
46
|
+
return from(updateActions);
|
|
47
|
+
}
|
|
48
|
+
return of(fetchCompletedTransactionsFailure({
|
|
49
|
+
error: response.status,
|
|
50
|
+
selectedPeriod,
|
|
51
|
+
}));
|
|
52
|
+
}), catchError((error) => of(fetchCompletedTransactionsFailure({
|
|
53
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch completed transactions errored: ' +
|
|
54
|
+
JSON.stringify(error)),
|
|
55
|
+
selectedPeriod,
|
|
56
|
+
}))));
|
|
57
|
+
}));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { concat, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { toMonthYearPeriodId } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { createZeniAPIStatus } from '../../../../responsePayload';
|
|
6
|
+
import { fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, } from '../../reducers/missingReceiptsViewReducer';
|
|
7
|
+
import { fetchBatchDetailsByIds } from './fetchMultipleBatchDetailsEpic';
|
|
8
|
+
const MORE_BATCH_PAGE_SIZE = 4;
|
|
9
|
+
export const fetchMoreBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchMoreBatchDetails.match), mergeMap(() => {
|
|
10
|
+
const state = state$.value;
|
|
11
|
+
const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
|
|
12
|
+
const currentTenant = getCurrentTenant(state);
|
|
13
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
14
|
+
if (selectedPeriod == null) {
|
|
15
|
+
return of(fetchMoreBatchDetailsComplete());
|
|
16
|
+
}
|
|
17
|
+
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
18
|
+
const batchList = bulkUpload.batchListByPeriod[periodId] ?? [];
|
|
19
|
+
const unfetchedBatchIds = batchList
|
|
20
|
+
.filter((batch) => batch.status === 'completed' &&
|
|
21
|
+
bulkUpload.batchDetailsById[batch.batchId] == null)
|
|
22
|
+
.map((batch) => batch.batchId);
|
|
23
|
+
if (unfetchedBatchIds.length === 0) {
|
|
24
|
+
return of(fetchMoreBatchDetailsComplete());
|
|
25
|
+
}
|
|
26
|
+
const nextPage = unfetchedBatchIds.slice(0, MORE_BATCH_PAGE_SIZE);
|
|
27
|
+
return concat(fetchBatchDetailsByIds(nextPage, zeniAPI), of(fetchMoreBatchDetailsComplete())).pipe(catchError((error) => of(fetchMoreBatchDetailsFailure({
|
|
28
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch more batch details errored out: ' +
|
|
29
|
+
JSON.stringify(error)),
|
|
30
|
+
}))));
|
|
31
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { EMPTY, from } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
4
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
|
+
import { extractTransactionPayloadsFromBatchFiles, toBatchDetails, } from '../../payload/missingReceiptsPayload';
|
|
6
|
+
import { fetchBulkUploadBatchesSuccess, storeBatchDetails, } from '../../reducers/missingReceiptsViewReducer';
|
|
7
|
+
const INITIAL_BATCH_PAGE_SIZE = 4;
|
|
8
|
+
export function fetchBatchDetailsByIds(batchIds, zeniAPI) {
|
|
9
|
+
if (batchIds.length === 0) {
|
|
10
|
+
return EMPTY;
|
|
11
|
+
}
|
|
12
|
+
return from(batchIds).pipe(mergeMap((batchId) => zeniAPI
|
|
13
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/batches/${batchId}`)
|
|
14
|
+
.pipe(mergeMap((response) => {
|
|
15
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
16
|
+
const actions = [];
|
|
17
|
+
const transactionPayloads = extractTransactionPayloadsFromBatchFiles(response.data.files);
|
|
18
|
+
if (transactionPayloads.length > 0) {
|
|
19
|
+
actions.push(updateTransactions(transactionPayloads, (value) => value.transaction_id));
|
|
20
|
+
}
|
|
21
|
+
actions.push(storeBatchDetails(toBatchDetails(response.data, zeniAPI.apiEndPoints.fileMicroServiceBaseUrl)));
|
|
22
|
+
return from(actions);
|
|
23
|
+
}
|
|
24
|
+
return EMPTY;
|
|
25
|
+
}), catchError((error) => {
|
|
26
|
+
console.error(`Failed to fetch batch details for ${batchId}:`, createZeniAPIStatus('Unexpected Error', 'Fetch batch details errored out: ' +
|
|
27
|
+
JSON.stringify(error)));
|
|
28
|
+
return EMPTY;
|
|
29
|
+
})), 5));
|
|
30
|
+
}
|
|
31
|
+
export const fetchMultipleBatchDetailsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchBulkUploadBatchesSuccess.match), mergeMap((action) => {
|
|
32
|
+
const batchList = action.payload.batchList;
|
|
33
|
+
const { batchDetailsById } = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
|
|
34
|
+
const completedBatchIds = batchList
|
|
35
|
+
.filter((batch) => batch.status === 'completed' &&
|
|
36
|
+
batchDetailsById[batch.batchId] == null)
|
|
37
|
+
.map((batch) => batch.batchId);
|
|
38
|
+
return fetchBatchDetailsByIds(completedBatchIds.slice(0, INITIAL_BATCH_PAGE_SIZE), zeniAPI);
|
|
39
|
+
}));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, debounceTime, filter, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
4
|
+
import { toManualSearchResult, } from '../../payload/missingReceiptsPayload';
|
|
5
|
+
import { searchTransactionsForManualMatch, searchTransactionsForManualMatchFailure, searchTransactionsForManualMatchSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
6
|
+
export const searchTransactionsForManualMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(searchTransactionsForManualMatch.match), debounceTime(300), switchMap((action) => {
|
|
7
|
+
const { query } = action.payload;
|
|
8
|
+
const searchQuery = JSON.stringify({
|
|
9
|
+
search_text: query,
|
|
10
|
+
search_fields: ['date', 'amount', 'vendor_name'],
|
|
11
|
+
});
|
|
12
|
+
const encodedQuery = encodeURIComponent(searchQuery);
|
|
13
|
+
return zeniAPI
|
|
14
|
+
.getJSON(`${zeniAPI.apiEndPoints.searchMicroServiceBaseUrl}/1.0/transaction-search?query=${encodedQuery}`)
|
|
15
|
+
.pipe(switchMap((response) => {
|
|
16
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
17
|
+
const results = response.data.transactions.map(toManualSearchResult);
|
|
18
|
+
return of(searchTransactionsForManualMatchSuccess(results));
|
|
19
|
+
}
|
|
20
|
+
return of(searchTransactionsForManualMatchFailure({
|
|
21
|
+
error: response.status,
|
|
22
|
+
}));
|
|
23
|
+
}), catchError((error) => of(searchTransactionsForManualMatchFailure({
|
|
24
|
+
error: createZeniAPIStatus('Unexpected Error', 'Search transactions for manual match errored: ' +
|
|
25
|
+
JSON.stringify(error)),
|
|
26
|
+
}))));
|
|
27
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { of, timer } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap, takeUntil, takeWhile, } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
5
|
+
import { isSuccessResponse } from '../../../../responsePayload';
|
|
6
|
+
import { toBatchListItem, } from '../../payload/missingReceiptsPayload';
|
|
7
|
+
import { bulkUploadReceiptsSuccess, clearBulkUpload, fetchBulkUploadBatchDetails, fetchBulkUploadBatchesSuccess, pusherBatchStatusUpdate, } from '../../reducers/missingReceiptsViewReducer';
|
|
8
|
+
export const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.status === 'completed'), mergeMap(() => of(fetchBulkUploadBatchDetails())));
|
|
9
|
+
const FALLBACK_POLL_INTERVAL_MS = 10000;
|
|
10
|
+
export const pollBulkUploadBatchStatusEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), switchMap((action) => {
|
|
11
|
+
const { batchId } = action.payload;
|
|
12
|
+
return timer(0, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(actions$.pipe(filter((a) => clearBulkUpload.match(a) ||
|
|
13
|
+
(pusherBatchStatusUpdate.match(a) &&
|
|
14
|
+
a.payload.status === 'completed')))), switchMap(() => {
|
|
15
|
+
const state = state$.value;
|
|
16
|
+
const { expenseAutomationViewState: { selectedPeriodByTenantId }, } = state;
|
|
17
|
+
const currentTenant = getCurrentTenant(state);
|
|
18
|
+
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
19
|
+
const period = convertToPeriod(selectedPeriod);
|
|
20
|
+
return zeniAPI
|
|
21
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipts/batches?start_date=${period.start}&end_date=${period.end}`)
|
|
22
|
+
.pipe(mergeMap((response) => {
|
|
23
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
24
|
+
const batchList = response.data.batches.map(toBatchListItem);
|
|
25
|
+
const currentBatch = batchList.find((b) => b.batchId === batchId);
|
|
26
|
+
if (currentBatch?.status === 'completed') {
|
|
27
|
+
return [
|
|
28
|
+
fetchBulkUploadBatchesSuccess({
|
|
29
|
+
batchList,
|
|
30
|
+
selectedPeriod,
|
|
31
|
+
}),
|
|
32
|
+
fetchBulkUploadBatchDetails(),
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return [];
|
|
37
|
+
}), catchError(() => of()));
|
|
38
|
+
}), takeWhile((emittedAction) => {
|
|
39
|
+
if (fetchBulkUploadBatchDetails.match(emittedAction)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}, true));
|
|
44
|
+
}));
|
|
@@ -1 +1,96 @@
|
|
|
1
|
-
|
|
1
|
+
import { toURL } from '../../../commonPayloadTypes/urlPayload';
|
|
2
|
+
// -- Converter functions --
|
|
3
|
+
export function toBatchFile(payload, filesEndPoint) {
|
|
4
|
+
return {
|
|
5
|
+
attachmentId: payload.attachment_id,
|
|
6
|
+
candidates: payload.candidates?.map((c) => ({
|
|
7
|
+
transactionId: c.transaction_id,
|
|
8
|
+
matchScore: c.match_score,
|
|
9
|
+
})),
|
|
10
|
+
fileDownloadUrl: payload.file_id != null && filesEndPoint != null
|
|
11
|
+
? `${filesEndPoint}/1.0/files/${payload.file_id}?query=${encodeURIComponent(JSON.stringify({ download_file: true }))}`
|
|
12
|
+
: null,
|
|
13
|
+
fileId: payload.file_id,
|
|
14
|
+
filePreviewUrl: payload.file_preview_url,
|
|
15
|
+
filename: payload.filename,
|
|
16
|
+
matchSource: payload.match_source,
|
|
17
|
+
matchedTransactionId: payload.matched_transaction?.transaction_id,
|
|
18
|
+
status: payload.status,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function extractTransactionPayloadsFromBatchFiles(files) {
|
|
22
|
+
const seen = new Set();
|
|
23
|
+
const payloads = [];
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
if (file.matched_transaction != null) {
|
|
26
|
+
const id = file.matched_transaction.transaction_id;
|
|
27
|
+
if (!seen.has(id)) {
|
|
28
|
+
seen.add(id);
|
|
29
|
+
payloads.push(matchedTransactionPayloadToSupportedTransactionPayload(file.matched_transaction));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (file.candidates != null) {
|
|
33
|
+
for (const candidate of file.candidates) {
|
|
34
|
+
const id = candidate.transaction_id;
|
|
35
|
+
if (!seen.has(id)) {
|
|
36
|
+
seen.add(id);
|
|
37
|
+
payloads.push(matchedTransactionPayloadToSupportedTransactionPayload(candidate));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return payloads;
|
|
43
|
+
}
|
|
44
|
+
function matchedTransactionPayloadToSupportedTransactionPayload(payload) {
|
|
45
|
+
return {
|
|
46
|
+
transaction_id: payload.transaction_id,
|
|
47
|
+
transaction_type: payload.transaction_type ?? 'expense',
|
|
48
|
+
transaction_date: payload.transaction_date ?? '',
|
|
49
|
+
currency_code: payload.currency_code,
|
|
50
|
+
total_amount: payload.amount,
|
|
51
|
+
vendor_name: payload.vendor_name,
|
|
52
|
+
logo: payload.vendor_logo == null ? undefined : toURL(payload.vendor_logo),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export function toBatchSummary(payload) {
|
|
56
|
+
return {
|
|
57
|
+
failed: payload.failed,
|
|
58
|
+
matched: payload.matched,
|
|
59
|
+
noMatch: payload.no_match,
|
|
60
|
+
possibleMatches: payload.possible_matches,
|
|
61
|
+
total: payload.total,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function toBatchDetails(payload, filesEndPoint) {
|
|
65
|
+
return {
|
|
66
|
+
batchId: payload.batch_id,
|
|
67
|
+
createdAt: payload.created_at,
|
|
68
|
+
files: payload.files.map((f) => toBatchFile(f, filesEndPoint)),
|
|
69
|
+
status: payload.status,
|
|
70
|
+
summary: toBatchSummary(payload.summary),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function toBatchListItem(payload) {
|
|
74
|
+
return {
|
|
75
|
+
batchId: payload.batch_id,
|
|
76
|
+
createdAt: payload.created_at,
|
|
77
|
+
failedCount: payload.failed_count,
|
|
78
|
+
matchedCount: payload.matched_count,
|
|
79
|
+
noMatchCount: payload.no_match_count,
|
|
80
|
+
possibleMatchesCount: payload.possible_matches_count,
|
|
81
|
+
status: payload.status,
|
|
82
|
+
totalFiles: payload.total_files,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export function toManualSearchResult(payload) {
|
|
86
|
+
return {
|
|
87
|
+
amount: payload.amount,
|
|
88
|
+
currencyCode: payload.currency,
|
|
89
|
+
entityId: payload.entity_id,
|
|
90
|
+
memo: payload.memo,
|
|
91
|
+
transactionDate: payload.transaction_date,
|
|
92
|
+
transactionId: payload.transaction_id,
|
|
93
|
+
transactionType: payload.transaction_type,
|
|
94
|
+
vendorName: payload.vendor_name,
|
|
95
|
+
};
|
|
96
|
+
}
|