@zeniai/client-epic-state 4.19.37-betaVR1 → 4.19.37-betaVR11
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.
Potentially problematic release.
This version of @zeniai/client-epic-state might be problematic. Click here for more details.
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/epic.d.ts +3 -1
- package/lib/epic.js +3 -1
- package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/esm/epic.js +3 -1
- package/lib/esm/index.js +2 -2
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +4 -8
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +37 -13
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +3 -3
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +41 -11
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +23 -14
- 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/watchBulkUploadBatchStatusEpic.js +35 -27
- package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +12 -80
- package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +79 -44
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +25 -5
- package/lib/index.d.ts +3 -3
- package/lib/index.js +35 -32
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +2 -5
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +3 -7
- package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +2 -1
- package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +36 -12
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +3 -3
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +3 -2
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +40 -10
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +22 -13
- 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/watchBulkUploadBatchStatusEpic.d.ts +3 -10
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +33 -25
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +19 -84
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +12 -82
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +15 -5
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +80 -45
- package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +5 -1
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +25 -5
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +7 -3
- package/package.json +2 -2
- package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js
CHANGED
|
@@ -1,16 +1,46 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
2
|
+
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
3
5
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
4
6
|
import { toBatchListItem, } from '../../payload/missingReceiptsPayload';
|
|
5
7
|
import { fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
6
|
-
export const fetchBulkUploadBatchesEpic = (actions$,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
+
}));
|
|
11
21
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
const period = convertToPeriod(selectedPeriod);
|
|
23
|
+
const queryParam = {
|
|
24
|
+
start_date: period.start,
|
|
25
|
+
end_date: period.end,
|
|
26
|
+
sort_order: 'desc',
|
|
27
|
+
};
|
|
28
|
+
return zeniAPI
|
|
29
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
|
|
30
|
+
.pipe(mergeMap((response) => {
|
|
31
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
32
|
+
return of(fetchBulkUploadBatchesSuccess({
|
|
33
|
+
batchList: response.data.batches.map(toBatchListItem),
|
|
34
|
+
selectedPeriod,
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
return of(fetchBulkUploadBatchesFailure({
|
|
38
|
+
error: response.status,
|
|
39
|
+
selectedPeriod,
|
|
40
|
+
}));
|
|
41
|
+
}), catchError((error) => of(fetchBulkUploadBatchesFailure({
|
|
42
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch bulk upload batches errored out: ' +
|
|
43
|
+
JSON.stringify(error)),
|
|
44
|
+
selectedPeriod,
|
|
45
|
+
}))));
|
|
46
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js
CHANGED
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
import { from, of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
|
|
3
|
-
import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
|
|
3
|
+
import { convertToPeriod, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
4
5
|
import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
|
|
5
6
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
6
|
-
import { completedTransactionPayloadToSupportedTransactionPayload, } from '../../payload/missingReceiptsPayload';
|
|
7
7
|
import { fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, } from '../../reducers/missingReceiptsViewReducer';
|
|
8
8
|
export const fetchCompletedTransactionsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchCompletedTransactions.match), switchMap((action) => {
|
|
9
9
|
const state = state$.value;
|
|
10
|
-
const { expenseAutomationMissingReceiptsViewState: { bulkUpload }, } = state;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
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([]);
|
|
15
18
|
}
|
|
16
19
|
const period = convertToPeriod(selectedPeriod);
|
|
17
|
-
queryPayload
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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;
|
|
21
30
|
}
|
|
22
31
|
const encodedQuery = encodeURIComponent(JSON.stringify(queryPayload));
|
|
23
32
|
return zeniAPI
|
|
24
|
-
.getJSON(`${zeniAPI.apiEndPoints.
|
|
33
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/receipt-agent/transactions/completed?query=${encodedQuery}`)
|
|
25
34
|
.pipe(mergeMap((response) => {
|
|
26
35
|
if (isSuccessResponse(response) && response.data != null) {
|
|
27
|
-
const transactionPayloads = response.data.transactions.map(completedTransactionPayloadToSupportedTransactionPayload);
|
|
28
36
|
const transactionIds = response.data.transactions.map((t) => t.transaction_id);
|
|
29
37
|
const updateActions = [];
|
|
30
|
-
updateActions.push(updateTransactions(
|
|
38
|
+
updateActions.push(updateTransactions(response.data.transactions, (value) => value.transaction_id));
|
|
31
39
|
updateActions.push(fetchCompletedTransactionsSuccess({
|
|
40
|
+
isInitialLoad,
|
|
32
41
|
transactionIds,
|
|
33
42
|
nextPageToken: response.data.next_page_token,
|
|
34
43
|
totalCount: response.data.total_count,
|
|
@@ -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/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
|
+
}));
|
package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js
CHANGED
|
@@ -1,39 +1,47 @@
|
|
|
1
1
|
import { of, timer } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap, switchMap, takeUntil, takeWhile, } from 'rxjs/operators';
|
|
3
|
+
import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
|
|
4
|
+
import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
|
|
3
5
|
import { isSuccessResponse } from '../../../../responsePayload';
|
|
4
|
-
import {
|
|
5
|
-
import { bulkUploadReceiptsSuccess, clearBulkUpload, fetchBulkUploadBatchDetails,
|
|
6
|
-
/**
|
|
7
|
-
* Watches batch status using two strategies:
|
|
8
|
-
* 1. Pusher (primary): Reacts to `pusherBatchStatusUpdate` dispatched by the UI layer
|
|
9
|
-
* when a Pusher event arrives. Immediately fetches full details on completion.
|
|
10
|
-
* 2. Polling (fallback): Starts a relaxed 10s poll after upload success as a safety net
|
|
11
|
-
* in case the Pusher event is missed. Stops on completion or `clearBulkUpload`.
|
|
12
|
-
*/
|
|
13
|
-
// Pusher-driven: when Pusher delivers a completed status, fetch details
|
|
6
|
+
import { toBatchListItem, } from '../../payload/missingReceiptsPayload';
|
|
7
|
+
import { bulkUploadReceiptsSuccess, clearBulkUpload, fetchBulkUploadBatchDetails, fetchBulkUploadBatchesSuccess, pusherBatchStatusUpdate, } from '../../reducers/missingReceiptsViewReducer';
|
|
14
8
|
export const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.status === 'completed'), mergeMap(() => of(fetchBulkUploadBatchDetails())));
|
|
15
|
-
// Polling fallback: relaxed interval as safety net
|
|
16
9
|
const FALLBACK_POLL_INTERVAL_MS = 10000;
|
|
17
|
-
export const pollBulkUploadBatchStatusEpic = (actions$,
|
|
10
|
+
export const pollBulkUploadBatchStatusEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), switchMap((action) => {
|
|
18
11
|
const { batchId } = action.payload;
|
|
19
12
|
return timer(0, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(actions$.pipe(filter((a) => clearBulkUpload.match(a) ||
|
|
20
13
|
(pusherBatchStatusUpdate.match(a) &&
|
|
21
|
-
a.payload.status === 'completed')))), switchMap(() =>
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
+
const queryParam = {
|
|
21
|
+
start_date: period.start,
|
|
22
|
+
end_date: period.end,
|
|
23
|
+
sort_order: 'desc',
|
|
24
|
+
};
|
|
25
|
+
return zeniAPI
|
|
26
|
+
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
|
|
27
|
+
.pipe(mergeMap((response) => {
|
|
28
|
+
if (isSuccessResponse(response) && response.data != null) {
|
|
29
|
+
const batchList = response.data.batches.map(toBatchListItem);
|
|
30
|
+
const currentBatch = batchList.find((b) => b.batchId === batchId);
|
|
31
|
+
if (currentBatch?.status === 'completed') {
|
|
32
|
+
return [
|
|
33
|
+
fetchBulkUploadBatchesSuccess({
|
|
34
|
+
batchList,
|
|
35
|
+
selectedPeriod,
|
|
36
|
+
}),
|
|
37
|
+
fetchBulkUploadBatchDetails(),
|
|
38
|
+
];
|
|
39
|
+
}
|
|
31
40
|
}
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (fetchBulkUploadBatchDetails.match(action)) {
|
|
41
|
+
return [];
|
|
42
|
+
}), catchError(() => of()));
|
|
43
|
+
}), takeWhile((emittedAction) => {
|
|
44
|
+
if (fetchBulkUploadBatchDetails.match(emittedAction)) {
|
|
37
45
|
return false;
|
|
38
46
|
}
|
|
39
47
|
return true;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { toURL } from '../../../commonPayloadTypes/urlPayload';
|
|
1
2
|
// -- Converter functions --
|
|
2
|
-
export function toBatchFile(payload) {
|
|
3
|
+
export function toBatchFile(payload, filesEndPoint) {
|
|
3
4
|
return {
|
|
4
5
|
attachmentId: payload.attachment_id,
|
|
5
6
|
candidates: payload.candidates?.map((c) => ({
|
|
6
7
|
transactionId: c.transaction_id,
|
|
7
8
|
matchScore: c.match_score,
|
|
8
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,
|
|
9
13
|
fileId: payload.file_id,
|
|
10
14
|
filePreviewUrl: payload.file_preview_url,
|
|
11
15
|
filename: payload.filename,
|
|
16
|
+
matchSource: payload.match_source,
|
|
12
17
|
matchedTransactionId: payload.matched_transaction?.transaction_id,
|
|
13
18
|
status: payload.status,
|
|
14
19
|
};
|
|
@@ -39,10 +44,12 @@ export function extractTransactionPayloadsFromBatchFiles(files) {
|
|
|
39
44
|
function matchedTransactionPayloadToSupportedTransactionPayload(payload) {
|
|
40
45
|
return {
|
|
41
46
|
transaction_id: payload.transaction_id,
|
|
42
|
-
|
|
47
|
+
transaction_type: payload.transaction_type ?? 'expense',
|
|
48
|
+
transaction_date: payload.transaction_date ?? '',
|
|
43
49
|
currency_code: payload.currency_code,
|
|
44
50
|
total_amount: payload.amount,
|
|
45
51
|
vendor_name: payload.vendor_name,
|
|
52
|
+
logo: payload.vendor_logo == null ? undefined : toURL(payload.vendor_logo),
|
|
46
53
|
};
|
|
47
54
|
}
|
|
48
55
|
export function toBatchSummary(payload) {
|
|
@@ -54,18 +61,11 @@ export function toBatchSummary(payload) {
|
|
|
54
61
|
total: payload.total,
|
|
55
62
|
};
|
|
56
63
|
}
|
|
57
|
-
export function
|
|
58
|
-
return {
|
|
59
|
-
batchId: payload.batch_id,
|
|
60
|
-
progress: payload.progress,
|
|
61
|
-
status: payload.status,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
export function toBatchDetails(payload) {
|
|
64
|
+
export function toBatchDetails(payload, filesEndPoint) {
|
|
65
65
|
return {
|
|
66
66
|
batchId: payload.batch_id,
|
|
67
67
|
createdAt: payload.created_at,
|
|
68
|
-
files: payload.files.map(toBatchFile),
|
|
68
|
+
files: payload.files.map((f) => toBatchFile(f, filesEndPoint)),
|
|
69
69
|
status: payload.status,
|
|
70
70
|
summary: toBatchSummary(payload.summary),
|
|
71
71
|
};
|
|
@@ -85,7 +85,7 @@ export function toBatchListItem(payload) {
|
|
|
85
85
|
export function toManualSearchResult(payload) {
|
|
86
86
|
return {
|
|
87
87
|
amount: payload.amount,
|
|
88
|
-
|
|
88
|
+
currencyCode: payload.currency,
|
|
89
89
|
entityId: payload.entity_id,
|
|
90
90
|
memo: payload.memo,
|
|
91
91
|
transactionDate: payload.transaction_date,
|
|
@@ -94,71 +94,3 @@ export function toManualSearchResult(payload) {
|
|
|
94
94
|
vendorName: payload.vendor_name,
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
|
-
function completedTransactionAttachmentToAttachmentPayload(payload) {
|
|
98
|
-
return {
|
|
99
|
-
attachment_create_time: payload.attachment_create_time ?? '',
|
|
100
|
-
attachment_id: payload.attachment_id,
|
|
101
|
-
attachment_update_time: payload.attachment_update_time ?? '',
|
|
102
|
-
content_type: payload.content_type,
|
|
103
|
-
file_checksum: null,
|
|
104
|
-
file_download_url: payload.file_download_url,
|
|
105
|
-
file_name: payload.file_name,
|
|
106
|
-
file_size: payload.file_size,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
function completedTransactionLineToLinePayload(payload) {
|
|
110
|
-
return {
|
|
111
|
-
amount: payload.amount,
|
|
112
|
-
line_description: payload.line_description,
|
|
113
|
-
line_detail_type: payload.line_detail_type,
|
|
114
|
-
line_id: payload.line_id,
|
|
115
|
-
categorization_status: payload.categorization_status,
|
|
116
|
-
line_detail: {
|
|
117
|
-
account: {
|
|
118
|
-
account_id: payload.line_detail.account?.account_id ?? '',
|
|
119
|
-
account_name: payload.line_detail.account?.account_name ?? '',
|
|
120
|
-
labels: [],
|
|
121
|
-
coa_id: payload.line_detail.account?.coa_id,
|
|
122
|
-
qbo_id: payload.line_detail.account?.qbo_id,
|
|
123
|
-
},
|
|
124
|
-
class: {
|
|
125
|
-
accounting_class_id: payload.line_detail.class?.accounting_class_id ?? '',
|
|
126
|
-
accounting_class_name: payload.line_detail.class?.accounting_class_name ?? '',
|
|
127
|
-
accounting_class_number: payload.line_detail.class?.accounting_class_number,
|
|
128
|
-
fully_qualified_accounting_class_name: payload.line_detail.class?.fully_qualified_accounting_class_name,
|
|
129
|
-
qbo_id: payload.line_detail.class?.qbo_id,
|
|
130
|
-
},
|
|
131
|
-
line_detail_type: payload.line_detail_type,
|
|
132
|
-
customer: payload.line_detail.customer != null
|
|
133
|
-
? {
|
|
134
|
-
customer_id: payload.line_detail.customer.customer_id,
|
|
135
|
-
customer_name: payload.line_detail.customer.customer_name,
|
|
136
|
-
qbo_id: payload.line_detail.customer.qbo_id,
|
|
137
|
-
}
|
|
138
|
-
: undefined,
|
|
139
|
-
vendor: payload.line_detail.vendor != null
|
|
140
|
-
? {
|
|
141
|
-
vendor_id: payload.line_detail.vendor.vendor_id,
|
|
142
|
-
vendor_name: payload.line_detail.vendor.vendor_name,
|
|
143
|
-
}
|
|
144
|
-
: undefined,
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
export function completedTransactionPayloadToSupportedTransactionPayload(payload) {
|
|
149
|
-
return {
|
|
150
|
-
transaction_id: payload.transaction_id,
|
|
151
|
-
transaction_type: payload.transaction_type,
|
|
152
|
-
transaction_date: payload.transaction_date,
|
|
153
|
-
transaction_type_name: payload.transaction_type_name,
|
|
154
|
-
currency_code: payload.currency_code,
|
|
155
|
-
currency_symbol: payload.currency_symbol,
|
|
156
|
-
total_amount: payload.total_amount,
|
|
157
|
-
vendor_id: payload.vendor_id,
|
|
158
|
-
vendor_name: payload.vendor_name,
|
|
159
|
-
account_id: payload.account_id,
|
|
160
|
-
account_name: payload.account_name,
|
|
161
|
-
attachments: payload.attachments.map(completedTransactionAttachmentToAttachmentPayload),
|
|
162
|
-
lines: payload.lines.map(completedTransactionLineToLinePayload),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
@@ -2,7 +2,8 @@ import { createSlice } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
3
3
|
export const initialBulkUploadState = {
|
|
4
4
|
batchDetailsById: {},
|
|
5
|
-
|
|
5
|
+
batchDetailsPaginationState: { fetchState: 'Not-Started', error: undefined },
|
|
6
|
+
batchListByPeriod: {},
|
|
6
7
|
batchListFetchState: { fetchState: 'Not-Started', error: undefined },
|
|
7
8
|
batchStatusById: {},
|
|
8
9
|
completedSubTab: 'all',
|
|
@@ -175,10 +176,6 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
175
176
|
};
|
|
176
177
|
draft.bulkUpload.phase = 'idle';
|
|
177
178
|
},
|
|
178
|
-
updateBulkUploadBatchStatus(draft, action) {
|
|
179
|
-
const batchStatus = action.payload;
|
|
180
|
-
draft.bulkUpload.batchStatusById[batchStatus.batchId] = batchStatus;
|
|
181
|
-
},
|
|
182
179
|
pusherBatchStatusUpdate(draft, action) {
|
|
183
180
|
const batchStatus = action.payload;
|
|
184
181
|
draft.bulkUpload.batchStatusById[batchStatus.batchId] = batchStatus;
|
|
@@ -196,14 +193,44 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
196
193
|
fetchBulkUploadBatchDetailsFailure(draft, _action) {
|
|
197
194
|
draft.bulkUpload.phase = 'completed';
|
|
198
195
|
},
|
|
199
|
-
|
|
200
|
-
|
|
196
|
+
storeBatchDetails(draft, action) {
|
|
197
|
+
const details = action.payload;
|
|
198
|
+
draft.bulkUpload.batchDetailsById[details.batchId] = details;
|
|
199
|
+
},
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
201
|
+
fetchMoreBatchDetails(_draft) {
|
|
202
|
+
_draft.bulkUpload.batchDetailsPaginationState = {
|
|
201
203
|
fetchState: 'In-Progress',
|
|
202
204
|
error: undefined,
|
|
203
205
|
};
|
|
204
206
|
},
|
|
207
|
+
fetchMoreBatchDetailsComplete(draft) {
|
|
208
|
+
draft.bulkUpload.batchDetailsPaginationState = {
|
|
209
|
+
fetchState: 'Completed',
|
|
210
|
+
error: undefined,
|
|
211
|
+
};
|
|
212
|
+
},
|
|
213
|
+
fetchMoreBatchDetailsFailure(draft, action) {
|
|
214
|
+
draft.bulkUpload.batchDetailsPaginationState = {
|
|
215
|
+
fetchState: 'Error',
|
|
216
|
+
error: action.payload.error,
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
fetchBulkUploadBatches: {
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
221
|
+
reducer(draft, _action) {
|
|
222
|
+
draft.bulkUpload.batchListFetchState = {
|
|
223
|
+
fetchState: 'In-Progress',
|
|
224
|
+
error: undefined,
|
|
225
|
+
};
|
|
226
|
+
},
|
|
227
|
+
prepare(cacheOverride = false) {
|
|
228
|
+
return { payload: { cacheOverride } };
|
|
229
|
+
},
|
|
230
|
+
},
|
|
205
231
|
fetchBulkUploadBatchesSuccess(draft, action) {
|
|
206
|
-
|
|
232
|
+
const periodId = toMonthYearPeriodId(action.payload.selectedPeriod);
|
|
233
|
+
draft.bulkUpload.batchListByPeriod[periodId] = action.payload.batchList;
|
|
207
234
|
draft.bulkUpload.batchListFetchState = {
|
|
208
235
|
fetchState: 'Completed',
|
|
209
236
|
error: undefined,
|
|
@@ -223,8 +250,8 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
223
250
|
error: undefined,
|
|
224
251
|
};
|
|
225
252
|
},
|
|
226
|
-
prepare(batchId, attachmentId, transactionId) {
|
|
227
|
-
return { payload: { batchId, attachmentId, transactionId } };
|
|
253
|
+
prepare(batchId, attachmentId, transactionId, transactionType, fileName) {
|
|
254
|
+
return { payload: { batchId, attachmentId, transactionId, transactionType, fileName } };
|
|
228
255
|
},
|
|
229
256
|
},
|
|
230
257
|
confirmBulkUploadMatchSuccess(draft, action) {
|
|
@@ -237,12 +264,18 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
237
264
|
if (details != null) {
|
|
238
265
|
const file = details.files.find((f) => f.attachmentId === attachmentId);
|
|
239
266
|
if (file != null) {
|
|
267
|
+
const originalStatus = file.status;
|
|
240
268
|
file.status = 'matched';
|
|
241
269
|
file.matchedTransactionId = transactionId;
|
|
242
270
|
file.candidates = undefined;
|
|
271
|
+
details.summary.matched += 1;
|
|
272
|
+
if (originalStatus === 'no_match') {
|
|
273
|
+
details.summary.noMatch = Math.max(0, details.summary.noMatch - 1);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
details.summary.possibleMatches = Math.max(0, details.summary.possibleMatches - 1);
|
|
277
|
+
}
|
|
243
278
|
}
|
|
244
|
-
details.summary.matched += 1;
|
|
245
|
-
details.summary.possibleMatches = Math.max(0, details.summary.possibleMatches - 1);
|
|
246
279
|
}
|
|
247
280
|
},
|
|
248
281
|
confirmBulkUploadMatchFailure(draft, action) {
|
|
@@ -297,43 +330,28 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
297
330
|
// -- Completed Transactions Actions --
|
|
298
331
|
fetchCompletedTransactions: {
|
|
299
332
|
reducer(draft, action) {
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
draft.bulkUpload.completedTransactionsByPeriod[periodId] = {
|
|
315
|
-
fetchState: { fetchState: 'In-Progress', error: undefined },
|
|
316
|
-
nextPageToken: null,
|
|
317
|
-
totalCount: 0,
|
|
318
|
-
transactionIds: [],
|
|
319
|
-
};
|
|
333
|
+
const { pageToken } = action.payload;
|
|
334
|
+
if (pageToken != null) {
|
|
335
|
+
const periods = draft.bulkUpload.completedTransactionsByPeriod;
|
|
336
|
+
for (const entry of Object.values(periods)) {
|
|
337
|
+
if (entry.nextPageToken === pageToken) {
|
|
338
|
+
entry.fetchState = {
|
|
339
|
+
fetchState: 'In-Progress',
|
|
340
|
+
error: undefined,
|
|
341
|
+
};
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
320
345
|
}
|
|
321
346
|
},
|
|
322
|
-
prepare(
|
|
323
|
-
return { payload: {
|
|
347
|
+
prepare(pageToken) {
|
|
348
|
+
return { payload: { pageToken } };
|
|
324
349
|
},
|
|
325
350
|
},
|
|
326
351
|
fetchCompletedTransactionsSuccess(draft, action) {
|
|
327
|
-
const { transactionIds, nextPageToken, totalCount, selectedPeriod } = action.payload;
|
|
352
|
+
const { transactionIds, nextPageToken, totalCount, selectedPeriod, isInitialLoad } = action.payload;
|
|
328
353
|
const periodId = toMonthYearPeriodId(selectedPeriod);
|
|
329
|
-
|
|
330
|
-
if (existing != null) {
|
|
331
|
-
existing.transactionIds.push(...transactionIds);
|
|
332
|
-
existing.nextPageToken = nextPageToken;
|
|
333
|
-
existing.totalCount = totalCount;
|
|
334
|
-
existing.fetchState = { fetchState: 'Completed', error: undefined };
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
354
|
+
if (isInitialLoad) {
|
|
337
355
|
draft.bulkUpload.completedTransactionsByPeriod[periodId] = {
|
|
338
356
|
transactionIds,
|
|
339
357
|
nextPageToken,
|
|
@@ -341,6 +359,23 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
341
359
|
fetchState: { fetchState: 'Completed', error: undefined },
|
|
342
360
|
};
|
|
343
361
|
}
|
|
362
|
+
else {
|
|
363
|
+
const existing = draft.bulkUpload.completedTransactionsByPeriod[periodId];
|
|
364
|
+
if (existing != null) {
|
|
365
|
+
existing.transactionIds.push(...transactionIds);
|
|
366
|
+
existing.nextPageToken = nextPageToken;
|
|
367
|
+
existing.totalCount = totalCount;
|
|
368
|
+
existing.fetchState = { fetchState: 'Completed', error: undefined };
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
draft.bulkUpload.completedTransactionsByPeriod[periodId] = {
|
|
372
|
+
transactionIds,
|
|
373
|
+
nextPageToken,
|
|
374
|
+
totalCount,
|
|
375
|
+
fetchState: { fetchState: 'Completed', error: undefined },
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
}
|
|
344
379
|
},
|
|
345
380
|
fetchCompletedTransactionsFailure(draft, action) {
|
|
346
381
|
const periodId = toMonthYearPeriodId(action.payload.selectedPeriod);
|
|
@@ -364,7 +399,7 @@ const expenseAutomationMissingReceiptsView = createSlice({
|
|
|
364
399
|
});
|
|
365
400
|
export const { fetchMissingReceipts, fetchMissingReceiptsSuccess, fetchMissingReceiptsFailure, uploadMissingReceiptSuccess, updateMissingReceiptUploadState, updateMissingReceiptsUIState, markMissingReceiptAsDone, clearExpenseAutomationMissingReceiptsView,
|
|
366
401
|
// Bulk Upload
|
|
367
|
-
bulkUploadReceipts, updateBulkUploadProgress, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure,
|
|
402
|
+
bulkUploadReceipts, updateBulkUploadProgress, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, pusherBatchStatusUpdate, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults,
|
|
368
403
|
// Completed Transactions
|
|
369
404
|
fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, } = expenseAutomationMissingReceiptsView.actions;
|
|
370
405
|
export default expenseAutomationMissingReceiptsView.reducer;
|