@zeniai/client-epic-state 4.19.84-betaVR15 → 4.19.84-betaVR2
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/epic.js +1 -1
- package/lib/esm/epic.js +2 -2
- package/lib/esm/index.js +3 -7
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +5 -10
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +1 -1
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +1 -1
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +4 -14
- package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +3 -43
- package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +9 -38
- package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +22 -54
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +35 -57
- package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +0 -39
- package/lib/index.d.ts +3 -4
- package/lib/index.js +33 -48
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +0 -3
- package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +3 -8
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +1 -1
- package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +1 -1
- package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +3 -13
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +2 -14
- package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +3 -44
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +1 -12
- package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +9 -39
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +5 -11
- package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +22 -54
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +35 -57
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +9 -27
- package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +1 -49
- package/package.json +1 -1
- package/lib/esm/view/expenseAutomationView/bulkUploadTiming.js +0 -10
- package/lib/view/expenseAutomationView/bulkUploadTiming.d.ts +0 -10
- package/lib/view/expenseAutomationView/bulkUploadTiming.js +0 -13
package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pollBulkUploadBatchStatusEpic = exports.
|
|
3
|
+
exports.pollBulkUploadBatchStatusEpic = exports.pusherBatchStatusCompletionEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
-
const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
|
|
7
6
|
const transactionReducer_1 = require("../../../../entity/transaction/transactionReducer");
|
|
8
7
|
const responsePayload_1 = require("../../../../responsePayload");
|
|
9
|
-
const bulkUploadTiming_1 = require("../../bulkUploadTiming");
|
|
10
8
|
const missingReceiptsPayload_1 = require("../../payload/missingReceiptsPayload");
|
|
11
9
|
const missingReceiptsViewReducer_1 = require("../../reducers/missingReceiptsViewReducer");
|
|
12
10
|
/** First poll after upload; then interval while batch not resolved via Pusher or API. */
|
|
@@ -24,38 +22,9 @@ const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe((0, operator
|
|
|
24
22
|
(0, missingReceiptsViewReducer_1.requestMissingReceiptsTabNavigation)({ tab: 'unmatched' }),
|
|
25
23
|
])));
|
|
26
24
|
exports.pusherBatchStatusCompletionEpic = pusherBatchStatusCompletionEpic;
|
|
27
|
-
/**
|
|
28
|
-
* If Pusher and batch-details are delayed beyond {@link BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS},
|
|
29
|
-
* force `phase` to `completed` (dismiss automatching banner) and refresh the batch list.
|
|
30
|
-
* Cancels when the batch completes normally, bulk state is cleared, or another upload supersedes.
|
|
31
|
-
*/
|
|
32
|
-
const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.bulkUploadReceiptsSuccess.match), (0, operators_1.mergeMap)((action) => {
|
|
33
|
-
const { batchId } = action.payload;
|
|
34
|
-
return (0, rxjs_1.timer)(bulkUploadTiming_1.BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS).pipe((0, operators_1.mergeMap)(() => {
|
|
35
|
-
const bulk = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
|
|
36
|
-
if (bulk.phase !== 'matching' ||
|
|
37
|
-
bulk.currentBatchId !== batchId) {
|
|
38
|
-
return rxjs_1.EMPTY;
|
|
39
|
-
}
|
|
40
|
-
// eslint-disable-next-line no-console
|
|
41
|
-
console.warn('[bulk-upload] Automatching wait exceeded timeout; releasing UI', { batchId });
|
|
42
|
-
return (0, rxjs_1.from)([
|
|
43
|
-
(0, missingReceiptsViewReducer_1.bulkUploadAutomatchingTimedOut)(batchId),
|
|
44
|
-
(0, missingReceiptsViewReducer_1.fetchBulkUploadBatches)({ cacheOverride: true }),
|
|
45
|
-
]);
|
|
46
|
-
}), (0, operators_1.takeUntil)((0, rxjs_1.merge)(actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.clearBulkUpload.match)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.pusherBatchStatusUpdate.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId &&
|
|
47
|
-
a.payload.status === 'completed')), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchDetailsSuccess.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId)))));
|
|
48
|
-
}));
|
|
49
|
-
exports.bulkUploadAutomatchingTimeoutEpic = bulkUploadAutomatchingTimeoutEpic;
|
|
50
|
-
/**
|
|
51
|
-
* Fallback polling when Pusher is slow or unavailable. Network errors on a poll tick show one
|
|
52
|
-
* error snackbar per upload session (first failure only) so the user is not spammed every
|
|
53
|
-
* interval; Pusher or a later successful poll still completes the flow.
|
|
54
|
-
*/
|
|
55
25
|
const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.bulkUploadReceiptsSuccess.match), (0, operators_1.mergeMap)((action) => {
|
|
56
26
|
const { batchId } = action.payload;
|
|
57
|
-
|
|
58
|
-
return (0, rxjs_1.timer)(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe((0, operators_1.takeUntil)((0, rxjs_1.merge)(actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.clearBulkUpload.match)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.pusherBatchStatusUpdate.match), (0, operators_1.filter)((action) => action.payload.batchId === batchId)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchDetailsSuccess.match), (0, operators_1.filter)((action) => action.payload.batchId === batchId)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.bulkUploadAutomatchingTimedOut.match), (0, operators_1.filter)((action) => action.payload.batchId === batchId)))), (0, operators_1.switchMap)(() => zeniAPI
|
|
27
|
+
return (0, rxjs_1.timer)(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe((0, operators_1.takeUntil)((0, rxjs_1.merge)(actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.clearBulkUpload.match)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.pusherBatchStatusUpdate.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId)), actions$.pipe((0, operators_1.filter)(missingReceiptsViewReducer_1.fetchBulkUploadBatchDetailsSuccess.match), (0, operators_1.filter)((a) => a.payload.batchId === batchId)))), (0, operators_1.switchMap)(() => zeniAPI
|
|
59
28
|
.getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
|
|
60
29
|
.pipe((0, operators_1.mergeMap)((response) => {
|
|
61
30
|
/** Same batch-details URL; polls until `status` is completed (Pusher may win first). */
|
|
@@ -73,16 +42,6 @@ const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.p
|
|
|
73
42
|
}
|
|
74
43
|
}
|
|
75
44
|
return rxjs_1.EMPTY;
|
|
76
|
-
}), (0, operators_1.catchError)(() =>
|
|
77
|
-
if (!pollErrorNotified) {
|
|
78
|
-
pollErrorNotified = true;
|
|
79
|
-
return (0, rxjs_1.of)((0, snackbarReducer_1.openSnackbar)({
|
|
80
|
-
messageSection: 'receipts_upload',
|
|
81
|
-
messageText: 'failed',
|
|
82
|
-
type: 'error',
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
return rxjs_1.EMPTY;
|
|
86
|
-
}))));
|
|
45
|
+
}), (0, operators_1.catchError)(() => (0, rxjs_1.of)()))));
|
|
87
46
|
}));
|
|
88
47
|
exports.pollBulkUploadBatchStatusEpic = pollBulkUploadBatchStatusEpic;
|
|
@@ -3,7 +3,7 @@ import { TransactionPayload } from '../../../entity/transaction/payloadTypes/tra
|
|
|
3
3
|
import { SupportedTransactionPayload } from '../../../entity/transaction/transactionState';
|
|
4
4
|
import { ZeniAPIResponse } from '../../../responsePayload';
|
|
5
5
|
import type { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
6
|
-
import {
|
|
6
|
+
import type { BatchDetails, BatchFile, BatchListItem, BatchStatus, BatchSummary, ManualSearchResult } from '../types/missingReceiptsViewState';
|
|
7
7
|
export interface MissingReceiptsQueryPayload {
|
|
8
8
|
end_date: string;
|
|
9
9
|
is_attachment_missing_only: boolean;
|
|
@@ -54,11 +54,6 @@ export interface MatchedTransactionPayload {
|
|
|
54
54
|
export interface MatchCandidatePayload extends MatchedTransactionPayload {
|
|
55
55
|
match_score: number;
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Wire payload for a batch file row. `status` may use legacy aliases (`matched`, `un_matched`,
|
|
59
|
-
* `possible_match`, `possible_matches`, etc.) until the backend is fully migrated; canonical
|
|
60
|
-
* values are applied in {@link parseBatchFileStatus} via {@link toBatchFile}.
|
|
61
|
-
*/
|
|
62
57
|
export interface BatchFilePayload {
|
|
63
58
|
attachment_id: string;
|
|
64
59
|
file_id: string;
|
|
@@ -83,12 +78,6 @@ export interface BatchDetailsResponsePayload {
|
|
|
83
78
|
};
|
|
84
79
|
}
|
|
85
80
|
export type BatchDetailsResponse = ZeniAPIResponse<BatchDetailsResponsePayload>;
|
|
86
|
-
/**
|
|
87
|
-
* Maps batch-details API `files[].status` strings to canonical {@link BatchFileStatus}.
|
|
88
|
-
* Legacy aliases are supported during rollout; unknown strings map to `failed` so Redux never
|
|
89
|
-
* holds untyped status values.
|
|
90
|
-
*/
|
|
91
|
-
export declare function parseBatchFileStatus(raw: string): BatchFileStatus;
|
|
92
81
|
export declare function toBatchFile(payload: BatchFilePayload, filesEndPoint?: string): BatchFile;
|
|
93
82
|
export declare function extractTransactionPayloadsFromBatchFiles(files: BatchFilePayload[]): SupportedTransactionPayload[];
|
|
94
83
|
export declare function toBatchSummary(payload: BatchDetailsResponsePayload['summary']): BatchSummary;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseBatchFileStatus = parseBatchFileStatus;
|
|
4
3
|
exports.toBatchFile = toBatchFile;
|
|
5
4
|
exports.extractTransactionPayloadsFromBatchFiles = extractTransactionPayloadsFromBatchFiles;
|
|
6
5
|
exports.toBatchSummary = toBatchSummary;
|
|
@@ -14,40 +13,13 @@ exports.toBatchListItem = toBatchListItem;
|
|
|
14
13
|
exports.supportedTransactionPayloadToManualSearchResult = supportedTransactionPayloadToManualSearchResult;
|
|
15
14
|
const urlPayload_1 = require("../../../commonPayloadTypes/urlPayload");
|
|
16
15
|
const transactionPayload_1 = require("../../../entity/transaction/payloadTypes/transactionPayload");
|
|
17
|
-
const missingReceiptsViewState_1 = require("../types/missingReceiptsViewState");
|
|
18
16
|
// -- Converter functions --
|
|
19
|
-
/**
|
|
20
|
-
* Maps batch-details API `files[].status` strings to canonical {@link BatchFileStatus}.
|
|
21
|
-
* Legacy aliases are supported during rollout; unknown strings map to `failed` so Redux never
|
|
22
|
-
* holds untyped status values.
|
|
23
|
-
*/
|
|
24
|
-
function parseBatchFileStatus(raw) {
|
|
25
|
-
const normalizedStatus = raw.trim().toLowerCase().replace(/-/g, '_');
|
|
26
|
-
switch (normalizedStatus) {
|
|
27
|
-
case 'exact_match':
|
|
28
|
-
case 'matched':
|
|
29
|
-
return 'exact_match';
|
|
30
|
-
case 'possible_matches':
|
|
31
|
-
case 'possible_match':
|
|
32
|
-
case 'possiblematch':
|
|
33
|
-
case 'un_matched':
|
|
34
|
-
case 'unmatched':
|
|
35
|
-
return 'possible_matches';
|
|
36
|
-
case 'no_match':
|
|
37
|
-
case 'nomatch':
|
|
38
|
-
return 'no_match';
|
|
39
|
-
case 'failed':
|
|
40
|
-
return 'failed';
|
|
41
|
-
default:
|
|
42
|
-
return 'failed';
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
17
|
function toBatchFile(payload, filesEndPoint) {
|
|
46
18
|
return {
|
|
47
19
|
attachmentId: payload.attachment_id,
|
|
48
|
-
candidates: payload.candidates?.map((
|
|
49
|
-
transactionId:
|
|
50
|
-
matchScore:
|
|
20
|
+
candidates: payload.candidates?.map((c) => ({
|
|
21
|
+
transactionId: c.transaction_id,
|
|
22
|
+
matchScore: c.match_score,
|
|
51
23
|
})),
|
|
52
24
|
fileDownloadUrl: payload.file_id != null && filesEndPoint != null
|
|
53
25
|
? `${filesEndPoint}/1.0/files/${payload.file_id}?query=${encodeURIComponent(JSON.stringify({ download_file: true }))}`
|
|
@@ -55,11 +27,9 @@ function toBatchFile(payload, filesEndPoint) {
|
|
|
55
27
|
fileId: payload.file_id,
|
|
56
28
|
filePreviewUrl: payload.file_preview_url,
|
|
57
29
|
filename: payload.filename,
|
|
58
|
-
matchSource: payload.match_source
|
|
59
|
-
? (0, missingReceiptsViewState_1.toMatchSource)(payload.match_source)
|
|
60
|
-
: undefined,
|
|
30
|
+
matchSource: payload.match_source,
|
|
61
31
|
matchedTransactionId: payload.matched_transaction?.transaction_id,
|
|
62
|
-
status:
|
|
32
|
+
status: payload.status,
|
|
63
33
|
};
|
|
64
34
|
}
|
|
65
35
|
function extractTransactionPayloadsFromBatchFiles(files) {
|
|
@@ -109,8 +79,8 @@ function toBatchDetails(payload, filesEndPoint) {
|
|
|
109
79
|
return {
|
|
110
80
|
batchId: payload.batch_id,
|
|
111
81
|
createdAt: payload.created_at,
|
|
112
|
-
files: payload.files.map((
|
|
113
|
-
status:
|
|
82
|
+
files: payload.files.map((f) => toBatchFile(f, filesEndPoint)),
|
|
83
|
+
status: payload.status,
|
|
114
84
|
summary: toBatchSummary(payload.summary),
|
|
115
85
|
};
|
|
116
86
|
}
|
|
@@ -124,7 +94,7 @@ function isBatchListStatusCompleted(status) {
|
|
|
124
94
|
* statuses for UI; only `completed` rows should trigger batch-details requests.
|
|
125
95
|
*/
|
|
126
96
|
function filterBatchListItemsForBatchDetailsFetch(batches) {
|
|
127
|
-
return batches.filter((
|
|
97
|
+
return batches.filter((b) => isBatchListStatusCompleted(b.status));
|
|
128
98
|
}
|
|
129
99
|
/**
|
|
130
100
|
* Batch details API response `status` field — only completed payloads should be stored from
|
|
@@ -135,7 +105,7 @@ function isBatchDetailsApiStatusCompleted(status) {
|
|
|
135
105
|
}
|
|
136
106
|
function findBatchListItemForBatchId(batchListByPeriod, batchId) {
|
|
137
107
|
for (const list of Object.values(batchListByPeriod)) {
|
|
138
|
-
const found = list.find((
|
|
108
|
+
const found = list.find((b) => b.batchId === batchId);
|
|
139
109
|
if (found != null) {
|
|
140
110
|
return found;
|
|
141
111
|
}
|
|
@@ -5,13 +5,11 @@ import { MonthYearPeriod, TimePeriod } from '../../../commonStateTypes/timePerio
|
|
|
5
5
|
import { TransactionPayload } from '../../../entity/transaction/payloadTypes/transactionPayload';
|
|
6
6
|
import { SupportedTransactionPayload } from '../../../entity/transaction/transactionState';
|
|
7
7
|
import { ZeniAPIStatus } from '../../../responsePayload';
|
|
8
|
-
import {
|
|
8
|
+
import type { BatchDetails, BatchListItem, BatchStatus, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CompletedSubTab, ManualSearchResult, MissingReceiptsViewState, MissingReceiptsViewUIState } from '../types/missingReceiptsViewState';
|
|
9
9
|
import type { MonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
10
10
|
export declare const getCompletedTransactionsCacheKey: (periodId: MonthYearPeriodId, sortKey: BulkUploadSortKey, sortOrder: SortOrder, subTab: CompletedSubTab) => string;
|
|
11
11
|
export declare const initialBulkUploadState: BulkUploadState;
|
|
12
12
|
export declare const initialState: MissingReceiptsViewState;
|
|
13
|
-
/** Epic trigger only; batch-details fetch is handled in epics. */
|
|
14
|
-
export declare const fetchBulkUploadBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails">;
|
|
15
13
|
export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[period: TimePeriod, minimumTransactionAmount: Amount, cacheOverride?: any, refreshViewInBackground?: any], {
|
|
16
14
|
period: TimePeriod;
|
|
17
15
|
minimumTransactionAmount: Amount;
|
|
@@ -38,15 +36,11 @@ export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCrea
|
|
|
38
36
|
batchId: ID;
|
|
39
37
|
}, "expenseAutomationMissingReceiptsView/bulkUploadReceiptsSuccess">, bulkUploadReceiptsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
40
38
|
error: ZeniAPIStatus;
|
|
41
|
-
}, "expenseAutomationMissingReceiptsView/bulkUploadReceiptsFailure">,
|
|
42
|
-
batchId: string;
|
|
43
|
-
}, "expenseAutomationMissingReceiptsView/bulkUploadAutomatchingTimedOut", never, never>, pusherBatchStatusUpdate: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchStatus, "expenseAutomationMissingReceiptsView/pusherBatchStatusUpdate">, requestMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
39
|
+
}, "expenseAutomationMissingReceiptsView/bulkUploadReceiptsFailure">, pusherBatchStatusUpdate: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchStatus, "expenseAutomationMissingReceiptsView/pusherBatchStatusUpdate">, requestMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
44
40
|
tab: BulkUploadResultsTab;
|
|
45
|
-
}, "expenseAutomationMissingReceiptsView/requestMissingReceiptsTabNavigation">, clearMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearMissingReceiptsTabNavigation">, fetchBulkUploadBatchDetailsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsSuccess">, fetchBulkUploadBatchDetailsFailure: import("@reduxjs/toolkit").
|
|
46
|
-
error: ZeniAPIStatus;
|
|
47
|
-
}], {
|
|
41
|
+
}, "expenseAutomationMissingReceiptsView/requestMissingReceiptsTabNavigation">, clearMissingReceiptsTabNavigation: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearMissingReceiptsTabNavigation">, fetchBulkUploadBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails">, fetchBulkUploadBatchDetailsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsSuccess">, fetchBulkUploadBatchDetailsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
48
42
|
error: ZeniAPIStatus;
|
|
49
|
-
}, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsFailure"
|
|
43
|
+
}, "expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetailsFailure">, storeBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithPayload<BatchDetails, "expenseAutomationMissingReceiptsView/storeBatchDetails">, batchDetailFetchFailed: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
50
44
|
batchId: ID;
|
|
51
45
|
}, "expenseAutomationMissingReceiptsView/batchDetailFetchFailed">, setInitialBatchDetailsLoading: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/setInitialBatchDetailsLoading">, fetchMoreBatchDetails: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchMoreBatchDetails">, fetchMoreBatchDetailsComplete: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/fetchMoreBatchDetailsComplete">, fetchMoreBatchDetailsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
52
46
|
error: ZeniAPIStatus;
|
|
@@ -74,7 +68,7 @@ export declare const fetchMissingReceipts: import("@reduxjs/toolkit").ActionCrea
|
|
|
74
68
|
transactionId: ID;
|
|
75
69
|
}, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchSuccess">, confirmBulkUploadMatchFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
76
70
|
error: ZeniAPIStatus;
|
|
77
|
-
}, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchFailure">, setBulkUploadResultsTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<
|
|
71
|
+
}, "expenseAutomationMissingReceiptsView/confirmBulkUploadMatchFailure">, setBulkUploadResultsTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<BulkUploadResultsTab, "expenseAutomationMissingReceiptsView/setBulkUploadResultsTab">, setBulkUploadCompletedSubTab: import("@reduxjs/toolkit").ActionCreatorWithPayload<CompletedSubTab, "expenseAutomationMissingReceiptsView/setBulkUploadCompletedSubTab">, setBulkUploadSortConfig: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
78
72
|
sortKey: BulkUploadSortKey;
|
|
79
73
|
sortOrder: SortOrder;
|
|
80
74
|
}, "expenseAutomationMissingReceiptsView/setBulkUploadSortConfig">, clearBulkUpload: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationMissingReceiptsView/clearBulkUpload">, searchTransactionsForManualMatch: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[query: string, pageToken?: string | null | undefined], {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var _a;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.fetchCompletedTransactionsFailure = exports.fetchCompletedTransactionsSuccess = exports.fetchCompletedTransactions = exports.acknowledgeBulkUploadConfirmMatchComplete = exports.clearManualSearchResults = exports.searchTransactionsForManualMatchFailure = exports.searchTransactionsForManualMatchSuccess = exports.searchTransactionsForManualMatch = exports.clearBulkUpload = exports.setBulkUploadSortConfig = exports.setBulkUploadCompletedSubTab = exports.setBulkUploadResultsTab = exports.confirmBulkUploadMatchFailure = exports.confirmBulkUploadMatchSuccess = exports.confirmBulkUploadMatch = exports.fetchBulkUploadBatchesFailure = exports.fetchBulkUploadBatchesSuccess = exports.fetchBulkUploadBatches = exports.fetchMoreBatchDetailsFailure = exports.fetchMoreBatchDetailsComplete = exports.fetchMoreBatchDetails = exports.setInitialBatchDetailsLoading = exports.batchDetailFetchFailed = exports.storeBatchDetails = exports.fetchBulkUploadBatchDetailsFailure = exports.fetchBulkUploadBatchDetailsSuccess = exports.
|
|
4
|
+
exports.fetchCompletedTransactionsFailure = exports.fetchCompletedTransactionsSuccess = exports.fetchCompletedTransactions = exports.acknowledgeBulkUploadConfirmMatchComplete = exports.clearManualSearchResults = exports.searchTransactionsForManualMatchFailure = exports.searchTransactionsForManualMatchSuccess = exports.searchTransactionsForManualMatch = exports.clearBulkUpload = exports.setBulkUploadSortConfig = exports.setBulkUploadCompletedSubTab = exports.setBulkUploadResultsTab = exports.confirmBulkUploadMatchFailure = exports.confirmBulkUploadMatchSuccess = exports.confirmBulkUploadMatch = exports.fetchBulkUploadBatchesFailure = exports.fetchBulkUploadBatchesSuccess = exports.fetchBulkUploadBatches = exports.fetchMoreBatchDetailsFailure = exports.fetchMoreBatchDetailsComplete = exports.fetchMoreBatchDetails = exports.setInitialBatchDetailsLoading = exports.batchDetailFetchFailed = exports.storeBatchDetails = exports.fetchBulkUploadBatchDetailsFailure = exports.fetchBulkUploadBatchDetailsSuccess = exports.fetchBulkUploadBatchDetails = exports.clearMissingReceiptsTabNavigation = exports.requestMissingReceiptsTabNavigation = exports.pusherBatchStatusUpdate = exports.bulkUploadReceiptsFailure = exports.bulkUploadReceiptsSuccess = exports.updateBulkUploadProgress = exports.bulkUploadReceipts = exports.clearExpenseAutomationMissingReceiptsView = exports.markMissingReceiptAsDone = exports.updateMissingReceiptsUIState = exports.updateMissingReceiptUploadState = exports.uploadMissingReceiptSuccess = exports.fetchMissingReceiptsFailure = exports.fetchMissingReceiptsSuccess = exports.fetchMissingReceipts = exports.initialState = exports.initialBulkUploadState = exports.getCompletedTransactionsCacheKey = void 0;
|
|
5
5
|
const toolkit_1 = require("@reduxjs/toolkit");
|
|
6
6
|
const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
|
|
7
|
-
const missingReceiptsViewState_1 = require("../types/missingReceiptsViewState");
|
|
8
7
|
const getCompletedTransactionsCacheKey = (periodId, sortKey, sortOrder, subTab) => `completed-${subTab}-${sortKey}-${sortOrder === 'ascending' ? 'asc' : 'desc'}-${periodId}`;
|
|
9
8
|
exports.getCompletedTransactionsCacheKey = getCompletedTransactionsCacheKey;
|
|
10
9
|
exports.initialBulkUploadState = {
|
|
@@ -56,8 +55,6 @@ exports.initialState = {
|
|
|
56
55
|
return this.fetchState == 'Completed';
|
|
57
56
|
},
|
|
58
57
|
};
|
|
59
|
-
/** Epic trigger only; batch-details fetch is handled in epics. */
|
|
60
|
-
exports.fetchBulkUploadBatchDetails = (0, toolkit_1.createAction)('expenseAutomationMissingReceiptsView/fetchBulkUploadBatchDetails');
|
|
61
58
|
const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
62
59
|
name: 'expenseAutomationMissingReceiptsView',
|
|
63
60
|
initialState: exports.initialState,
|
|
@@ -161,7 +158,8 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
161
158
|
},
|
|
162
159
|
// -- Bulk Upload Actions --
|
|
163
160
|
bulkUploadReceipts: {
|
|
164
|
-
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
162
|
+
reducer(draft, _action) {
|
|
165
163
|
draft.bulkUpload.phase = 'uploading';
|
|
166
164
|
draft.bulkUpload.uploadProgress = 0;
|
|
167
165
|
draft.bulkUpload.uploadStatus = {
|
|
@@ -178,7 +176,6 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
178
176
|
},
|
|
179
177
|
bulkUploadReceiptsSuccess(draft, action) {
|
|
180
178
|
draft.bulkUpload.currentBatchId = action.payload.batchId;
|
|
181
|
-
draft.bulkUpload.uploadProgress = 100;
|
|
182
179
|
draft.bulkUpload.uploadStatus = {
|
|
183
180
|
fetchState: 'Completed',
|
|
184
181
|
error: undefined,
|
|
@@ -192,18 +189,6 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
192
189
|
};
|
|
193
190
|
draft.bulkUpload.phase = 'idle';
|
|
194
191
|
},
|
|
195
|
-
bulkUploadAutomatchingTimedOut: {
|
|
196
|
-
reducer(draft, action) {
|
|
197
|
-
if (draft.bulkUpload.phase !== 'matching' ||
|
|
198
|
-
draft.bulkUpload.currentBatchId !== action.payload.batchId) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
draft.bulkUpload.phase = 'completed';
|
|
202
|
-
},
|
|
203
|
-
prepare(batchId) {
|
|
204
|
-
return { payload: { batchId } };
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
192
|
pusherBatchStatusUpdate(draft, action) {
|
|
208
193
|
const batchStatus = action.payload;
|
|
209
194
|
draft.bulkUpload.batchStatusById[batchStatus.batchId] = batchStatus;
|
|
@@ -224,18 +209,18 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
224
209
|
clearMissingReceiptsTabNavigation(draft) {
|
|
225
210
|
draft.pendingMissingReceiptsTabNavigation = null;
|
|
226
211
|
},
|
|
212
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
213
|
+
fetchBulkUploadBatchDetails(_draft) {
|
|
214
|
+
// trigger epic, no state change needed
|
|
215
|
+
},
|
|
227
216
|
fetchBulkUploadBatchDetailsSuccess(draft, action) {
|
|
228
217
|
const details = action.payload;
|
|
229
218
|
draft.bulkUpload.batchDetailsById[details.batchId] = details;
|
|
230
219
|
draft.bulkUpload.phase = 'completed';
|
|
231
220
|
},
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
},
|
|
236
|
-
prepare(payload) {
|
|
237
|
-
return { payload };
|
|
238
|
-
},
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
222
|
+
fetchBulkUploadBatchDetailsFailure(draft, _action) {
|
|
223
|
+
draft.bulkUpload.phase = 'completed';
|
|
239
224
|
},
|
|
240
225
|
storeBatchDetails(draft, action) {
|
|
241
226
|
const details = action.payload;
|
|
@@ -266,8 +251,8 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
266
251
|
error: undefined,
|
|
267
252
|
};
|
|
268
253
|
},
|
|
269
|
-
fetchMoreBatchDetails(
|
|
270
|
-
|
|
254
|
+
fetchMoreBatchDetails(_draft) {
|
|
255
|
+
_draft.bulkUpload.batchDetailsPaginationState = {
|
|
271
256
|
fetchState: 'In-Progress',
|
|
272
257
|
error: undefined,
|
|
273
258
|
};
|
|
@@ -305,11 +290,11 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
305
290
|
};
|
|
306
291
|
},
|
|
307
292
|
prepare(input) {
|
|
308
|
-
const
|
|
293
|
+
const o = input ?? {};
|
|
309
294
|
return {
|
|
310
295
|
payload: {
|
|
311
|
-
cacheOverride:
|
|
312
|
-
invalidateBatchDetailsCache:
|
|
296
|
+
cacheOverride: o.cacheOverride === true,
|
|
297
|
+
invalidateBatchDetailsCache: o.invalidateBatchDetailsCache === true,
|
|
313
298
|
},
|
|
314
299
|
};
|
|
315
300
|
},
|
|
@@ -343,7 +328,8 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
343
328
|
};
|
|
344
329
|
},
|
|
345
330
|
confirmBulkUploadMatch: {
|
|
346
|
-
|
|
331
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
332
|
+
reducer(draft, _action) {
|
|
347
333
|
draft.bulkUpload.confirmMatchStatus = {
|
|
348
334
|
fetchState: 'In-Progress',
|
|
349
335
|
error: undefined,
|
|
@@ -361,17 +347,17 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
361
347
|
};
|
|
362
348
|
const details = draft.bulkUpload.batchDetailsById[batchId];
|
|
363
349
|
if (details != null) {
|
|
364
|
-
const file = details.files.find((
|
|
350
|
+
const file = details.files.find((f) => f.attachmentId === attachmentId);
|
|
365
351
|
if (file != null) {
|
|
366
352
|
const originalStatus = file.status;
|
|
367
|
-
file.status = '
|
|
353
|
+
file.status = 'matched';
|
|
368
354
|
file.matchedTransactionId = transactionId;
|
|
369
355
|
file.candidates = undefined;
|
|
370
356
|
details.summary.matched += 1;
|
|
371
357
|
if (originalStatus === 'no_match') {
|
|
372
358
|
details.summary.noMatch = Math.max(0, details.summary.noMatch - 1);
|
|
373
359
|
}
|
|
374
|
-
else
|
|
360
|
+
else {
|
|
375
361
|
details.summary.possibleMatches = Math.max(0, details.summary.possibleMatches - 1);
|
|
376
362
|
}
|
|
377
363
|
}
|
|
@@ -403,24 +389,6 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
403
389
|
reducer(draft, action) {
|
|
404
390
|
const { query, pageToken } = action.payload;
|
|
405
391
|
const isLoadMore = pageToken != null;
|
|
406
|
-
const trimmed = query.trim();
|
|
407
|
-
/**
|
|
408
|
-
* Cleared or too-short query: no API (see epic). Reset fully (no In-Progress).
|
|
409
|
-
* Only bump `manualSearchUiResetKey` when clearing a real search — not when the UI
|
|
410
|
-
* dispatches `""` on every keystroke while length is below MIN (web-components always sends
|
|
411
|
-
* `onSearch("")` in that case), or ReceiptCard remounts and the input loses focus.
|
|
412
|
-
*/
|
|
413
|
-
if (!isLoadMore &&
|
|
414
|
-
trimmed.length < missingReceiptsViewState_1.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH) {
|
|
415
|
-
const hadActiveSearch = draft.bulkUpload.manualSearch.searchQuery.trim().length >=
|
|
416
|
-
missingReceiptsViewState_1.MIN_MANUAL_TRANSACTION_SEARCH_LENGTH ||
|
|
417
|
-
draft.bulkUpload.manualSearch.results.length > 0;
|
|
418
|
-
draft.bulkUpload.manualSearch = exports.initialBulkUploadState.manualSearch;
|
|
419
|
-
if (hadActiveSearch) {
|
|
420
|
-
draft.bulkUpload.manualSearchUiResetKey += 1;
|
|
421
|
-
}
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
424
392
|
draft.bulkUpload.manualSearch.searchQuery = query;
|
|
425
393
|
if (isLoadMore) {
|
|
426
394
|
draft.bulkUpload.manualSearch.isLoadingMore = true;
|
|
@@ -444,7 +412,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
444
412
|
const { append, nextPageToken, results, totalCount } = action.payload;
|
|
445
413
|
if (append) {
|
|
446
414
|
const merged = [...draft.bulkUpload.manualSearch.results, ...results];
|
|
447
|
-
const byId = new Map(merged.map((
|
|
415
|
+
const byId = new Map(merged.map((r) => [r.transactionId, r]));
|
|
448
416
|
draft.bulkUpload.manualSearch.results = Array.from(byId.values());
|
|
449
417
|
}
|
|
450
418
|
else {
|
|
@@ -549,7 +517,7 @@ const expenseAutomationMissingReceiptsView = (0, toolkit_1.createSlice)({
|
|
|
549
517
|
});
|
|
550
518
|
_a = expenseAutomationMissingReceiptsView.actions, exports.fetchMissingReceipts = _a.fetchMissingReceipts, exports.fetchMissingReceiptsSuccess = _a.fetchMissingReceiptsSuccess, exports.fetchMissingReceiptsFailure = _a.fetchMissingReceiptsFailure, exports.uploadMissingReceiptSuccess = _a.uploadMissingReceiptSuccess, exports.updateMissingReceiptUploadState = _a.updateMissingReceiptUploadState, exports.updateMissingReceiptsUIState = _a.updateMissingReceiptsUIState, exports.markMissingReceiptAsDone = _a.markMissingReceiptAsDone, exports.clearExpenseAutomationMissingReceiptsView = _a.clearExpenseAutomationMissingReceiptsView,
|
|
551
519
|
// Bulk Upload
|
|
552
|
-
exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.
|
|
520
|
+
exports.bulkUploadReceipts = _a.bulkUploadReceipts, exports.updateBulkUploadProgress = _a.updateBulkUploadProgress, exports.bulkUploadReceiptsSuccess = _a.bulkUploadReceiptsSuccess, exports.bulkUploadReceiptsFailure = _a.bulkUploadReceiptsFailure, exports.pusherBatchStatusUpdate = _a.pusherBatchStatusUpdate, exports.requestMissingReceiptsTabNavigation = _a.requestMissingReceiptsTabNavigation, exports.clearMissingReceiptsTabNavigation = _a.clearMissingReceiptsTabNavigation, exports.fetchBulkUploadBatchDetails = _a.fetchBulkUploadBatchDetails, exports.fetchBulkUploadBatchDetailsSuccess = _a.fetchBulkUploadBatchDetailsSuccess, exports.fetchBulkUploadBatchDetailsFailure = _a.fetchBulkUploadBatchDetailsFailure, exports.storeBatchDetails = _a.storeBatchDetails, exports.batchDetailFetchFailed = _a.batchDetailFetchFailed, exports.setInitialBatchDetailsLoading = _a.setInitialBatchDetailsLoading, exports.fetchMoreBatchDetails = _a.fetchMoreBatchDetails, exports.fetchMoreBatchDetailsComplete = _a.fetchMoreBatchDetailsComplete, exports.fetchMoreBatchDetailsFailure = _a.fetchMoreBatchDetailsFailure, exports.fetchBulkUploadBatches = _a.fetchBulkUploadBatches, exports.fetchBulkUploadBatchesSuccess = _a.fetchBulkUploadBatchesSuccess, exports.fetchBulkUploadBatchesFailure = _a.fetchBulkUploadBatchesFailure, exports.confirmBulkUploadMatch = _a.confirmBulkUploadMatch, exports.confirmBulkUploadMatchSuccess = _a.confirmBulkUploadMatchSuccess, exports.confirmBulkUploadMatchFailure = _a.confirmBulkUploadMatchFailure, exports.setBulkUploadResultsTab = _a.setBulkUploadResultsTab, exports.setBulkUploadCompletedSubTab = _a.setBulkUploadCompletedSubTab, exports.setBulkUploadSortConfig = _a.setBulkUploadSortConfig, exports.clearBulkUpload = _a.clearBulkUpload, exports.searchTransactionsForManualMatch = _a.searchTransactionsForManualMatch, exports.searchTransactionsForManualMatchSuccess = _a.searchTransactionsForManualMatchSuccess, exports.searchTransactionsForManualMatchFailure = _a.searchTransactionsForManualMatchFailure, exports.clearManualSearchResults = _a.clearManualSearchResults, exports.acknowledgeBulkUploadConfirmMatchComplete = _a.acknowledgeBulkUploadConfirmMatchComplete,
|
|
553
521
|
// Completed Transactions
|
|
554
522
|
exports.fetchCompletedTransactions = _a.fetchCompletedTransactions, exports.fetchCompletedTransactionsSuccess = _a.fetchCompletedTransactionsSuccess, exports.fetchCompletedTransactionsFailure = _a.fetchCompletedTransactionsFailure;
|
|
555
523
|
exports.default = expenseAutomationMissingReceiptsView.reducer;
|
|
@@ -11,7 +11,6 @@ const transactionSelector_1 = require("../../../entity/transaction/transactionSe
|
|
|
11
11
|
const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
|
|
12
12
|
const missingReceiptsPayload_1 = require("../payload/missingReceiptsPayload");
|
|
13
13
|
const missingReceiptsViewReducer_1 = require("../reducers/missingReceiptsViewReducer");
|
|
14
|
-
const missingReceiptsViewState_1 = require("../types/missingReceiptsViewState");
|
|
15
14
|
function getExpenseAutomationMissingReceiptsView(state) {
|
|
16
15
|
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
|
|
17
16
|
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
|
|
@@ -65,71 +64,50 @@ function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
65
64
|
: [];
|
|
66
65
|
/**
|
|
67
66
|
* Primary "Unmatched" batch = first completed batch in platform list order, preferring the
|
|
68
|
-
* first batch that still has
|
|
67
|
+
* first batch that still has un_matched/no_match work when any completed batch has such work.
|
|
69
68
|
* Batches without details yet: wait if the list row still reports unmatched work; otherwise skip
|
|
70
69
|
* so we do not block the whole tab while other rows are not fetched yet.
|
|
71
70
|
*/
|
|
72
71
|
const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
* upload), details are often not loaded yet — `unmatchedFiles` would empty while older batches
|
|
79
|
-
* moved to "past", so the primary "Unmatched Receipts" section vanished during auto-matching.
|
|
80
|
-
*/
|
|
81
|
-
const unmatchedSectionBatchId = (() => {
|
|
82
|
-
const phase = bulkUpload.phase;
|
|
83
|
-
if (phase !== 'matching' && phase !== 'uploading') {
|
|
84
|
-
return primaryBatchIdFromDetailsOrder;
|
|
85
|
-
}
|
|
86
|
-
const currentId = bulkUpload.currentBatchId;
|
|
87
|
-
if (currentId == null) {
|
|
88
|
-
return primaryBatchIdFromDetailsOrder;
|
|
89
|
-
}
|
|
90
|
-
const currentDetails = bulkUpload.batchDetailsById[currentId];
|
|
91
|
-
if (currentDetails != null &&
|
|
92
|
-
currentDetails.status === 'completed' &&
|
|
93
|
-
batchDetailsHasUnmatchedWork(currentDetails)) {
|
|
94
|
-
return currentId;
|
|
95
|
-
}
|
|
96
|
-
return primaryBatchIdFromDetailsOrder;
|
|
97
|
-
})();
|
|
98
|
-
const completedBatchesInApiOrder = batchList.filter((batchListItem) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(batchListItem.status));
|
|
72
|
+
/** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
|
|
73
|
+
const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
|
|
74
|
+
? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
|
|
75
|
+
: primaryBatchIdFromDetailsOrder;
|
|
76
|
+
const completedBatchesInApiOrder = batchList.filter((b) => (0, missingReceiptsPayload_1.isBatchListStatusCompleted)(b.status));
|
|
99
77
|
const currentBatchDetails = unmatchedSectionBatchId != null
|
|
100
78
|
? bulkUpload.batchDetailsById[unmatchedSectionBatchId]
|
|
101
79
|
: undefined;
|
|
102
80
|
const resolvedFiles = currentBatchDetails?.files.map((file) => resolveBatchFile(file, currentBatchDetails.batchId, transactionState));
|
|
103
81
|
const failedIds = new Set(bulkUpload.failedBatchDetailIds);
|
|
104
|
-
const hasMoreBatchDetails = completedBatchesInApiOrder.some((
|
|
105
|
-
!failedIds.has(
|
|
82
|
+
const hasMoreBatchDetails = completedBatchesInApiOrder.some((b) => bulkUpload.batchDetailsById[b.batchId] == null &&
|
|
83
|
+
!failedIds.has(b.batchId));
|
|
106
84
|
const getSortValue = (file) => {
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
85
|
+
const t = file.matchedTransaction;
|
|
86
|
+
if (t == null) {
|
|
109
87
|
return null;
|
|
110
88
|
}
|
|
111
89
|
switch (bulkUpload.sortKey) {
|
|
112
90
|
case 'vendor':
|
|
113
|
-
return (
|
|
91
|
+
return (t.vendorName ?? t.description)?.toLowerCase() ?? null;
|
|
114
92
|
case 'category': {
|
|
115
|
-
const line =
|
|
93
|
+
const line = t.lines?.[0];
|
|
116
94
|
return line?.account?.accountName?.toLowerCase() ?? null;
|
|
117
95
|
}
|
|
118
96
|
case 'class': {
|
|
119
|
-
const line =
|
|
97
|
+
const line = t.lines?.[0];
|
|
120
98
|
return line?.class?.className?.toLowerCase() ?? null;
|
|
121
99
|
}
|
|
122
100
|
case 'date':
|
|
123
|
-
return
|
|
101
|
+
return t.date.valueOf();
|
|
124
102
|
case 'amount':
|
|
125
|
-
return
|
|
103
|
+
return t.amount.amount;
|
|
126
104
|
default:
|
|
127
105
|
return null;
|
|
128
106
|
}
|
|
129
107
|
};
|
|
130
108
|
const bulkUploadSortDirection = bulkUpload.sortOrder === 'ascending' ? 'asc' : 'desc';
|
|
131
|
-
const matchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((
|
|
132
|
-
const unmatchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((
|
|
109
|
+
const matchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => f.status === 'matched') ?? [], getSortValue, bulkUploadSortDirection);
|
|
110
|
+
const unmatchedFiles = (0, orderBy_1.default)(resolvedFiles?.filter((f) => f.status === 'un_matched' || f.status === 'no_match') ?? [], getSortValue, bulkUploadSortDirection);
|
|
133
111
|
const progress = currentBatchStatus != null
|
|
134
112
|
? {
|
|
135
113
|
...currentBatchStatus.progress,
|
|
@@ -146,16 +124,16 @@ function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
146
124
|
* that has details loaded (otherwise past is empty and receipts vanish from the UI).
|
|
147
125
|
*/
|
|
148
126
|
const pastBatches = unmatchedSectionBatchId != null
|
|
149
|
-
? batchList.filter((
|
|
127
|
+
? batchList.filter((b) => b.batchId !== unmatchedSectionBatchId)
|
|
150
128
|
: batchList;
|
|
151
|
-
const pastUnmatchedFiles = pastBatches.flatMap((
|
|
152
|
-
const details = bulkUpload.batchDetailsById[
|
|
129
|
+
const pastUnmatchedFiles = pastBatches.flatMap((b) => {
|
|
130
|
+
const details = bulkUpload.batchDetailsById[b.batchId];
|
|
153
131
|
if (details == null) {
|
|
154
132
|
return [];
|
|
155
133
|
}
|
|
156
134
|
return details.files
|
|
157
|
-
.filter((
|
|
158
|
-
.map((
|
|
135
|
+
.filter((f) => f.status === 'un_matched' || f.status === 'no_match')
|
|
136
|
+
.map((f) => resolveBatchFile(f, b.batchId, transactionState));
|
|
159
137
|
});
|
|
160
138
|
const completedTransactionsCacheKey = monthYearPeriodId != null
|
|
161
139
|
? (0, missingReceiptsViewReducer_1.getCompletedTransactionsCacheKey)(monthYearPeriodId, bulkUpload.sortKey, bulkUpload.sortOrder, bulkUpload.completedSubTab)
|
|
@@ -174,11 +152,11 @@ function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
174
152
|
summary: currentBatchDetails.summary,
|
|
175
153
|
}
|
|
176
154
|
: undefined;
|
|
177
|
-
const manualSearchResults = bulkUpload.manualSearch.results.map((
|
|
178
|
-
const
|
|
155
|
+
const manualSearchResults = bulkUpload.manualSearch.results.map((r) => {
|
|
156
|
+
const t = (0, transactionSelector_1.getSupportedTransactionById)(transactionState, r.transactionId);
|
|
179
157
|
return {
|
|
180
|
-
...
|
|
181
|
-
vendorLogo:
|
|
158
|
+
...r,
|
|
159
|
+
vendorLogo: r.vendorLogo ?? t?.logo?.href,
|
|
182
160
|
};
|
|
183
161
|
});
|
|
184
162
|
return {
|
|
@@ -228,7 +206,7 @@ function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
228
206
|
};
|
|
229
207
|
}
|
|
230
208
|
function batchDetailsHasUnmatchedWork(details) {
|
|
231
|
-
return details.files.some((
|
|
209
|
+
return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
|
|
232
210
|
}
|
|
233
211
|
/** List row summary before batch details load — aligns with unmatched / possible-match work. */
|
|
234
212
|
function batchListItemHasUnmatchedWork(batch) {
|
|
@@ -245,17 +223,17 @@ function batchListItemHasUnmatchedWork(batch) {
|
|
|
245
223
|
*/
|
|
246
224
|
function getPrimaryBatchIdFromBatchListOrder(batchListInPlatformOrder, batchDetailsById, failedBatchDetailIds) {
|
|
247
225
|
const failedIds = new Set(failedBatchDetailIds);
|
|
248
|
-
const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((
|
|
249
|
-
if (failedIds.has(
|
|
226
|
+
const anyCompletedBatchHasUnmatchedWork = batchListInPlatformOrder.some((b) => {
|
|
227
|
+
if (failedIds.has(b.batchId)) {
|
|
250
228
|
return false;
|
|
251
229
|
}
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
254
|
-
|
|
255
|
-
batchDetailsHasUnmatchedWork(
|
|
230
|
+
const d = batchDetailsById[b.batchId];
|
|
231
|
+
if (d != null &&
|
|
232
|
+
d.status === 'completed' &&
|
|
233
|
+
batchDetailsHasUnmatchedWork(d)) {
|
|
256
234
|
return true;
|
|
257
235
|
}
|
|
258
|
-
return
|
|
236
|
+
return d == null && batchListItemHasUnmatchedWork(b);
|
|
259
237
|
});
|
|
260
238
|
for (const batch of batchListInPlatformOrder) {
|
|
261
239
|
if (failedIds.has(batch.batchId)) {
|
|
@@ -292,7 +270,7 @@ function resolveBatchFile(file, batchId, transactionState) {
|
|
|
292
270
|
? { transaction, matchScore: ref.matchScore }
|
|
293
271
|
: undefined;
|
|
294
272
|
})
|
|
295
|
-
.filter((
|
|
273
|
+
.filter((c) => c != null);
|
|
296
274
|
return {
|
|
297
275
|
attachmentId: file.attachmentId,
|
|
298
276
|
batchId,
|