@zeniai/client-epic-state 5.0.3-betaRD1 → 5.0.3-betaVR1

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.
@@ -1,15 +1,7 @@
1
1
  import { AiAccountantCustomer, AiAccountantEnrollment, AiAccountantJob } from './aiAccountantCustomerState';
2
- export interface AiAccountantModelAccuracyPayload {
3
- accuracy: number;
4
- model_id: string;
5
- passed: boolean;
6
- threshold: number;
7
- training_status: string;
8
- validated_at: string;
9
- }
10
2
  export interface AiAccountantEnrollmentPayload {
11
3
  status: string;
12
- accuracy?: Record<string, AiAccountantModelAccuracyPayload>;
4
+ accuracy?: Record<string, number>;
13
5
  latest_training?: string;
14
6
  latest_transaction_sync?: string;
15
7
  offboarded_at?: string;
@@ -4,24 +4,9 @@ exports.toAiAccountantJob = exports.toAiAccountantCustomer = exports.toAiAccount
4
4
  const zeniDayJS_1 = require("../../zeniDayJS");
5
5
  const aiAccountantCustomerState_1 = require("./aiAccountantCustomerState");
6
6
  // ── Mapping functions (payload → state) ──
7
- // Backend returns accuracy as a percent (0–100) inside a nested object; the UI
8
- // layer treats it as a 0–1 fraction. Normalize here and drop malformed entries.
9
- const toAccuracyByModel = (accuracyPayload) => {
10
- if (accuracyPayload == null) {
11
- return undefined;
12
- }
13
- const result = {};
14
- Object.entries(accuracyPayload).forEach(([model, entry]) => {
15
- const percent = entry?.accuracy;
16
- if (typeof percent === 'number' && Number.isFinite(percent)) {
17
- result[model] = percent / 100;
18
- }
19
- });
20
- return result;
21
- };
22
7
  const toAiAccountantEnrollment = (payload) => ({
23
8
  status: (0, aiAccountantCustomerState_1.toAiAccountantEnrollmentStatus)(payload.status),
24
- accuracy: toAccuracyByModel(payload.accuracy),
9
+ accuracy: payload.accuracy,
25
10
  latestTraining: payload.latest_training != null
26
11
  ? (0, zeniDayJS_1.date)(payload.latest_training)
27
12
  : undefined,
@@ -1,24 +1,9 @@
1
1
  import { date } from '../../zeniDayJS';
2
2
  import { toAiAccountantEnrollmentStatus, toAiAccountantJobStatus, toAiAccountantOperationType, } from './aiAccountantCustomerState';
3
3
  // ── Mapping functions (payload → state) ──
4
- // Backend returns accuracy as a percent (0–100) inside a nested object; the UI
5
- // layer treats it as a 0–1 fraction. Normalize here and drop malformed entries.
6
- const toAccuracyByModel = (accuracyPayload) => {
7
- if (accuracyPayload == null) {
8
- return undefined;
9
- }
10
- const result = {};
11
- Object.entries(accuracyPayload).forEach(([model, entry]) => {
12
- const percent = entry?.accuracy;
13
- if (typeof percent === 'number' && Number.isFinite(percent)) {
14
- result[model] = percent / 100;
15
- }
16
- });
17
- return result;
18
- };
19
4
  export const toAiAccountantEnrollment = (payload) => ({
20
5
  status: toAiAccountantEnrollmentStatus(payload.status),
21
- accuracy: toAccuracyByModel(payload.accuracy),
6
+ accuracy: payload.accuracy,
22
7
  latestTraining: payload.latest_training != null
23
8
  ? date(payload.latest_training)
24
9
  : undefined,
@@ -5,7 +5,7 @@ import { updateTransactions } from '../../../../entity/transaction/transactionRe
5
5
  import { isSuccessResponse } from '../../../../responsePayload';
6
6
  import { BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS } from '../../helpers/bulkUploadTiming';
7
7
  import { extractTransactionPayloadsFromBatchFiles, isBatchDetailsApiStatusCompleted, toBatchDetails, } from '../../payload/missingReceiptsPayload';
8
- import { bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, clearBulkUpload, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, restoreBulkUploadMatchingState, } from '../../reducers/missingReceiptsViewReducer';
8
+ import { bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, clearBulkUpload, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, restoreBulkUploadMatchingState, } from '../../reducers/missingReceiptsViewReducer';
9
9
  /** First poll after upload; then interval while batch not resolved via Pusher or API. */
10
10
  const FALLBACK_FIRST_DELAY_MS = 30000;
11
11
  /** Shorter first poll for restored sessions — batch may already be near completion. */
@@ -35,9 +35,17 @@ export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.
35
35
  if (bulk.phase !== 'matching' || bulk.currentBatchId !== batchId) {
36
36
  return EMPTY;
37
37
  }
38
+ /**
39
+ * Also request the single-batch details directly so the "X out of Y Receipts Matched"
40
+ * toast still fires when the backend actually completed between the last Pusher ping
41
+ * and this timeout. If Pusher already tagged the batch as still `processing`,
42
+ * `fetchBulkUploadBatchDetailsEpic`'s guard will skip the call and we simply rely on
43
+ * the list refresh to eventually populate details via `fetchMultipleBatchDetailsEpic`.
44
+ */
38
45
  return from([
39
46
  bulkUploadAutomatchingTimedOut(batchId),
40
47
  fetchBulkUploadBatches({ cacheOverride: true }),
48
+ fetchBulkUploadBatchDetails(),
41
49
  ]);
42
50
  }), takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((a) => a.payload.batchId === batchId &&
43
51
  a.payload.status === 'completed')), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((a) => a.payload.batchId === batchId)))));