@zeniai/client-epic-state 4.19.37-betaVR16 → 4.19.37-betaVR17

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.
@@ -9,6 +9,7 @@ export function fetchBatchDetailsByIds(batchIds, zeniAPI) {
9
9
  if (batchIds.length === 0) {
10
10
  return EMPTY;
11
11
  }
12
+ console.log('fetchBatchDetailsByIds', batchIds);
12
13
  return from(batchIds).pipe(mergeMap((batchId) => zeniAPI
13
14
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
14
15
  .pipe(mergeMap((response) => {
@@ -56,12 +56,15 @@ export function getExpenseAutomationMissingReceiptsView(state) {
56
56
  const batchList = monthYearPeriodId != null
57
57
  ? bulkUpload.batchListByPeriod[monthYearPeriodId] ?? []
58
58
  : [];
59
+ /** API returns newest-first (`sort_order: desc`); primary batch uses oldest-first order. */
60
+ const batchListChronological = orderBy(batchList, (b) => new Date(b.createdAt).valueOf(), 'asc');
59
61
  /**
60
- * Primary "Unmatched" batch = first batch in batch list order whose stored batchDetails
61
- * has status `completed`. If an earlier batch has no details yet (still loading), we return
62
- * undefined so we do not assign a later batch until ordering is known (avoids async reorder bugs).
62
+ * Primary "Unmatched" batch = first completed batch in chronological order, preferring the
63
+ * first batch that still has un_matched/no_match work when any completed batch has such work
64
+ * (so a newer fully-matched batch does not hide older unmatched receipts). If an earlier batch
65
+ * in that order has no details yet (still loading), we return undefined until it resolves.
63
66
  */
64
- const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
67
+ const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchListChronological, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
65
68
  /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
66
69
  const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
67
70
  ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
@@ -183,14 +186,26 @@ export function getExpenseAutomationMissingReceiptsView(state) {
183
186
  },
184
187
  };
185
188
  }
189
+ function batchDetailsHasUnmatchedWork(details) {
190
+ return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
191
+ }
186
192
  /**
187
- * First batch in `batchList` order with `batchDetailsById[id].status === 'completed'`.
188
- * Skips failed detail fetches. Stops at the first batch with no details yet (still loading)
189
- * so a later batch is never chosen as primary until earlier list rows are resolved.
193
+ * `batchList` must be in chronological order (oldest first). Picks the primary batch for the
194
+ * top "Unmatched" section. Skips failed detail fetches. Stops at the first batch with no details
195
+ * yet (still loading) so we do not choose a later batch until earlier chronological rows resolve.
190
196
  */
191
- function getPrimaryBatchIdFromBatchListOrder(batchList, batchDetailsById, failedBatchDetailIds) {
197
+ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetailsById, failedBatchDetailIds) {
192
198
  const failedIds = new Set(failedBatchDetailIds);
193
- for (const batch of batchList) {
199
+ const anyCompletedBatchHasUnmatchedWork = batchListChronological.some((b) => {
200
+ if (failedIds.has(b.batchId)) {
201
+ return false;
202
+ }
203
+ const d = batchDetailsById[b.batchId];
204
+ return (d != null &&
205
+ d.status === 'completed' &&
206
+ batchDetailsHasUnmatchedWork(d));
207
+ });
208
+ for (const batch of batchListChronological) {
194
209
  if (failedIds.has(batch.batchId)) {
195
210
  continue;
196
211
  }
@@ -198,9 +213,16 @@ function getPrimaryBatchIdFromBatchListOrder(batchList, batchDetailsById, failed
198
213
  if (details == null) {
199
214
  return undefined;
200
215
  }
201
- if (details.status === 'completed') {
202
- return batch.batchId;
216
+ if (details.status !== 'completed') {
217
+ continue;
218
+ }
219
+ if (anyCompletedBatchHasUnmatchedWork) {
220
+ if (batchDetailsHasUnmatchedWork(details)) {
221
+ return batch.batchId;
222
+ }
223
+ continue;
203
224
  }
225
+ return batch.batchId;
204
226
  }
205
227
  return undefined;
206
228
  }
@@ -13,6 +13,7 @@ function fetchBatchDetailsByIds(batchIds, zeniAPI) {
13
13
  if (batchIds.length === 0) {
14
14
  return rxjs_1.EMPTY;
15
15
  }
16
+ console.log('fetchBatchDetailsByIds', batchIds);
16
17
  return (0, rxjs_1.from)(batchIds).pipe((0, operators_1.mergeMap)((batchId) => zeniAPI
17
18
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
18
19
  .pipe((0, operators_1.mergeMap)((response) => {
@@ -62,12 +62,15 @@ function getExpenseAutomationMissingReceiptsView(state) {
62
62
  const batchList = monthYearPeriodId != null
63
63
  ? bulkUpload.batchListByPeriod[monthYearPeriodId] ?? []
64
64
  : [];
65
+ /** API returns newest-first (`sort_order: desc`); primary batch uses oldest-first order. */
66
+ const batchListChronological = (0, orderBy_1.default)(batchList, (b) => new Date(b.createdAt).valueOf(), 'asc');
65
67
  /**
66
- * Primary "Unmatched" batch = first batch in batch list order whose stored batchDetails
67
- * has status `completed`. If an earlier batch has no details yet (still loading), we return
68
- * undefined so we do not assign a later batch until ordering is known (avoids async reorder bugs).
68
+ * Primary "Unmatched" batch = first completed batch in chronological order, preferring the
69
+ * first batch that still has un_matched/no_match work when any completed batch has such work
70
+ * (so a newer fully-matched batch does not hide older unmatched receipts). If an earlier batch
71
+ * in that order has no details yet (still loading), we return undefined until it resolves.
69
72
  */
70
- const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchList, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
73
+ const primaryBatchIdFromDetailsOrder = getPrimaryBatchIdFromBatchListOrder(batchListChronological, bulkUpload.batchDetailsById, bulkUpload.failedBatchDetailIds);
71
74
  /** During upload/matching, the in-flight batch may not appear in batchList yet — prefer currentBatchId. */
72
75
  const unmatchedSectionBatchId = bulkUpload.phase === 'matching' || bulkUpload.phase === 'uploading'
73
76
  ? bulkUpload.currentBatchId ?? primaryBatchIdFromDetailsOrder
@@ -189,14 +192,26 @@ function getExpenseAutomationMissingReceiptsView(state) {
189
192
  },
190
193
  };
191
194
  }
195
+ function batchDetailsHasUnmatchedWork(details) {
196
+ return details.files.some((f) => f.status === 'un_matched' || f.status === 'no_match');
197
+ }
192
198
  /**
193
- * First batch in `batchList` order with `batchDetailsById[id].status === 'completed'`.
194
- * Skips failed detail fetches. Stops at the first batch with no details yet (still loading)
195
- * so a later batch is never chosen as primary until earlier list rows are resolved.
199
+ * `batchList` must be in chronological order (oldest first). Picks the primary batch for the
200
+ * top "Unmatched" section. Skips failed detail fetches. Stops at the first batch with no details
201
+ * yet (still loading) so we do not choose a later batch until earlier chronological rows resolve.
196
202
  */
197
- function getPrimaryBatchIdFromBatchListOrder(batchList, batchDetailsById, failedBatchDetailIds) {
203
+ function getPrimaryBatchIdFromBatchListOrder(batchListChronological, batchDetailsById, failedBatchDetailIds) {
198
204
  const failedIds = new Set(failedBatchDetailIds);
199
- for (const batch of batchList) {
205
+ const anyCompletedBatchHasUnmatchedWork = batchListChronological.some((b) => {
206
+ if (failedIds.has(b.batchId)) {
207
+ return false;
208
+ }
209
+ const d = batchDetailsById[b.batchId];
210
+ return (d != null &&
211
+ d.status === 'completed' &&
212
+ batchDetailsHasUnmatchedWork(d));
213
+ });
214
+ for (const batch of batchListChronological) {
200
215
  if (failedIds.has(batch.batchId)) {
201
216
  continue;
202
217
  }
@@ -204,9 +219,16 @@ function getPrimaryBatchIdFromBatchListOrder(batchList, batchDetailsById, failed
204
219
  if (details == null) {
205
220
  return undefined;
206
221
  }
207
- if (details.status === 'completed') {
208
- return batch.batchId;
222
+ if (details.status !== 'completed') {
223
+ continue;
224
+ }
225
+ if (anyCompletedBatchHasUnmatchedWork) {
226
+ if (batchDetailsHasUnmatchedWork(details)) {
227
+ return batch.batchId;
228
+ }
229
+ continue;
209
230
  }
231
+ return batch.batchId;
210
232
  }
211
233
  return undefined;
212
234
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "4.19.37-betaVR16",
3
+ "version": "4.19.37-betaVR17",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",