@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.
Files changed (70) hide show
  1. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  2. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  3. package/lib/epic.d.ts +10 -1
  4. package/lib/epic.js +10 -1
  5. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  6. package/lib/esm/epic.js +10 -1
  7. package/lib/esm/index.js +8 -6
  8. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +24 -0
  9. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +49 -0
  10. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +31 -0
  11. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +41 -0
  12. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +57 -0
  13. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +31 -0
  14. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +39 -0
  15. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +27 -0
  16. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +44 -0
  17. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +96 -1
  18. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +280 -1
  19. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +134 -1
  20. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.js +1 -10
  21. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +2 -4
  22. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +2 -5
  23. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.js +1 -10
  24. package/lib/esm/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +2 -4
  25. package/lib/esm/zeniAPI.js +41 -3
  26. package/lib/index.d.ts +11 -9
  27. package/lib/index.js +60 -32
  28. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +15 -0
  29. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +28 -0
  30. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +7 -0
  31. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +53 -0
  32. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.d.ts +8 -0
  33. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +35 -0
  34. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +7 -0
  35. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +45 -0
  36. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.d.ts +8 -0
  37. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +61 -0
  38. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.d.ts +8 -0
  39. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +35 -0
  40. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.d.ts +9 -0
  41. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +44 -0
  42. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.d.ts +6 -0
  43. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +31 -0
  44. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +8 -0
  45. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +49 -0
  46. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  47. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +98 -0
  48. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +102 -0
  49. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +53 -3
  50. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +281 -2
  51. package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +64 -1
  52. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.d.ts +1 -1
  53. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +133 -0
  54. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +106 -0
  55. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.d.ts +1 -1
  56. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewReducer.js +2 -11
  57. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +2 -4
  58. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelectorTypes.d.ts +0 -2
  59. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewState.d.ts +0 -1
  60. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.d.ts +0 -1
  61. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonPayload.js +2 -5
  62. package/lib/view/spendManagement/billPay/billPaySetupApproverView/types/commonState.d.ts +0 -2
  63. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.d.ts +1 -1
  64. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewReducer.js +2 -11
  65. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelector.js +2 -4
  66. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewSelectorTypes.d.ts +0 -2
  67. package/lib/view/spendManagement/reimbursement/remiSetupApproverView/remiSetupApproverViewState.d.ts +0 -1
  68. package/lib/zeniAPI.d.ts +9 -0
  69. package/lib/zeniAPI.js +40 -2
  70. package/package.json +2 -2
@@ -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
+ }));
@@ -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
+ }));
@@ -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
+ }));
@@ -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
+ }));
@@ -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
+ }));
@@ -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
- export {};
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
+ }