@zeniai/client-epic-state 5.1.21 → 5.1.23-betaNB1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +2 -1
  2. package/lib/commonStateTypes/viewAndReport/agingReportStateTypes.d.ts +1 -1
  3. package/lib/entity/accountRecon/accountReconPayload.d.ts +23 -1
  4. package/lib/entity/accountRecon/accountReconPayload.js +26 -1
  5. package/lib/entity/accountRecon/accountReconReducer.d.ts +5 -2
  6. package/lib/entity/accountRecon/accountReconReducer.js +33 -2
  7. package/lib/entity/accountRecon/accountReconSelector.d.ts +6 -1
  8. package/lib/entity/accountRecon/accountReconSelector.js +5 -0
  9. package/lib/entity/accountRecon/accountReconState.d.ts +22 -0
  10. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.d.ts +8 -0
  11. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
  12. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +8 -0
  13. package/lib/epic.d.ts +6 -1
  14. package/lib/epic.js +6 -1
  15. package/lib/esm/entity/accountRecon/accountReconPayload.js +26 -1
  16. package/lib/esm/entity/accountRecon/accountReconReducer.js +32 -1
  17. package/lib/esm/entity/accountRecon/accountReconSelector.js +5 -0
  18. package/lib/esm/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +10 -0
  19. package/lib/esm/epic.js +6 -1
  20. package/lib/esm/index.js +7 -7
  21. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +29 -3
  22. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +11 -0
  23. package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
  24. package/lib/esm/view/aiCfoView/epics/fetchSkillsEpic.js +34 -0
  25. package/lib/esm/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
  26. package/lib/esm/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +34 -0
  27. package/lib/esm/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +31 -0
  28. package/lib/esm/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +57 -0
  29. package/lib/esm/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
  30. package/lib/esm/view/expenseAutomationView/payload/reconciliationPayload.js +142 -0
  31. package/lib/esm/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
  32. package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +178 -8
  33. package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
  34. package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +27 -0
  35. package/lib/esm/view/expenseAutomationView/types/reconciliationViewState.js +29 -0
  36. package/lib/esm/view/opExByVendor/opExByVendorReducer.js +28 -5
  37. package/lib/esm/view/opExByVendor/opExByVendorSelector.js +1 -0
  38. package/lib/esm/view/opExByVendor/refreshOpExByVendorReportEpic.js +21 -0
  39. package/lib/index.d.ts +12 -12
  40. package/lib/index.js +56 -37
  41. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +14 -0
  42. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +8 -4
  43. package/lib/view/aiCfoView/aiCfoViewReducer.js +30 -4
  44. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +2 -1
  45. package/lib/view/aiCfoView/aiCfoViewSelector.js +12 -0
  46. package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -0
  47. package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -2
  48. package/lib/view/aiCfoView/epics/fetchSkillsEpic.d.ts +8 -0
  49. package/lib/view/aiCfoView/epics/fetchSkillsEpic.js +38 -0
  50. package/lib/view/aiCfoView/epics/submitQuestionEpic.js +7 -1
  51. package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.d.ts +6 -0
  52. package/lib/view/expenseAutomationView/epics/accountRecon/parseStatementEpic.js +38 -0
  53. package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.d.ts +26 -0
  54. package/lib/view/expenseAutomationView/epics/accountRecon/reparseStatementEpic.js +35 -0
  55. package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.d.ts +27 -0
  56. package/lib/view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic.js +61 -0
  57. package/lib/view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic.js +1 -0
  58. package/lib/view/expenseAutomationView/payload/fluxAnalysisPayload.d.ts +8 -0
  59. package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +163 -9
  60. package/lib/view/expenseAutomationView/payload/reconciliationPayload.js +146 -0
  61. package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.d.ts +2 -1
  62. package/lib/view/expenseAutomationView/reducers/fluxAnalysisViewReducer.js +6 -1
  63. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.d.ts +53 -3
  64. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +180 -9
  65. package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +7 -1
  66. package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +2 -1
  67. package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.d.ts +2 -0
  68. package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +29 -1
  69. package/lib/view/expenseAutomationView/types/fluxAnalysisViewState.d.ts +2 -0
  70. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +172 -0
  71. package/lib/view/expenseAutomationView/types/reconciliationViewState.js +30 -0
  72. package/lib/view/opExByVendor/opExByVendorReducer.d.ts +6 -1
  73. package/lib/view/opExByVendor/opExByVendorReducer.js +29 -6
  74. package/lib/view/opExByVendor/opExByVendorSelector.d.ts +1 -0
  75. package/lib/view/opExByVendor/opExByVendorSelector.js +1 -0
  76. package/lib/view/opExByVendor/opExByVendorState.d.ts +1 -0
  77. package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.d.ts +17 -0
  78. package/lib/view/opExByVendor/refreshOpExByVendorReportEpic.js +25 -0
  79. package/lib/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListState.d.ts +1 -1
  80. package/package.json +4 -2
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
3
3
  import { toReconciliationAccountSource } from '../../../entity/account/accountState';
4
4
  import { toBankStatusCodeType } from '../../../entity/accountRecon/accountReconState';
5
+ import { toReconciliationViewSummary, } from '../types/reconciliationViewState';
5
6
  // Initial state
6
7
  export const initialReconciliationTabsState = {
7
8
  balances: {
@@ -67,6 +68,7 @@ export const initialState = {
67
68
  refreshStatus: { fetchState: 'Not-Started', error: undefined },
68
69
  actionFetchState: initialActionFetchState,
69
70
  selectedAccountId: undefined,
71
+ statementProcessingFailed: false,
70
72
  statementUploadChosen: false,
71
73
  reconListUIState: {
72
74
  nodeCollapseState: {},
@@ -75,6 +77,7 @@ export const initialState = {
75
77
  },
76
78
  },
77
79
  excludedAccountIDs: [],
80
+ summary: undefined,
78
81
  };
79
82
  // Create slice with reducers
80
83
  const expenseAutomationReconciliationView = createSlice({
@@ -143,7 +146,7 @@ const expenseAutomationReconciliationView = createSlice({
143
146
  fetchReconciliationSuccess: {
144
147
  reducer(draft, action) {
145
148
  if (action.payload.accountId == null) {
146
- updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? []);
149
+ updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? [], action.payload.reconciliation.summary);
147
150
  }
148
151
  else if (action.payload.reconciliation.reconciliation.length > 0 &&
149
152
  action.payload.reconciliation.accounts.length > 0) {
@@ -287,6 +290,10 @@ const expenseAutomationReconciliationView = createSlice({
287
290
  updateSelectedDrawerAccountId: (draft, action) => {
288
291
  draft.selectedDrawerAccountId = action.payload.selectedDrawerAccountId;
289
292
  },
293
+ updateStatementProcessingFailed: (draft, action) => {
294
+ draft.statementProcessingFailed =
295
+ action.payload.statementProcessingFailed;
296
+ },
290
297
  initialiseLocalDataForSelectedAccountId: () => { },
291
298
  updateSelectedTab: (draft, action) => {
292
299
  const { selectedTab } = action.payload;
@@ -378,10 +385,22 @@ const expenseAutomationReconciliationView = createSlice({
378
385
  },
379
386
  uploadAccountStatement: (draft, action) => {
380
387
  const { accountId, selectedPeriod } = action.payload;
381
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementUploadStatus = {
382
- fetchState: 'In-Progress',
383
- error: undefined,
384
- };
388
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
389
+ if (accountRecon != null) {
390
+ accountRecon.statementUploadStatus = {
391
+ fetchState: 'In-Progress',
392
+ error: undefined,
393
+ };
394
+ accountRecon.parsedStatementData = undefined;
395
+ accountRecon.statementParseStatus = {
396
+ fetchState: 'Not-Started',
397
+ error: undefined,
398
+ };
399
+ accountRecon.reparseStatementStatus = {
400
+ fetchState: 'Not-Started',
401
+ error: undefined,
402
+ };
403
+ }
385
404
  },
386
405
  uploadAccountStatementSuccess: (draft, action) => {
387
406
  const { accountId, selectedPeriod } = action.payload;
@@ -419,6 +438,138 @@ const expenseAutomationReconciliationView = createSlice({
419
438
  error: action.payload.error,
420
439
  };
421
440
  },
441
+ parseStatement: (draft, action) => {
442
+ const { accountId, selectedPeriod } = action.payload;
443
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
444
+ if (accountRecon != null) {
445
+ accountRecon.parsedStatementData = undefined;
446
+ accountRecon.statementParseStatus = {
447
+ fetchState: 'In-Progress',
448
+ error: undefined,
449
+ };
450
+ }
451
+ },
452
+ parseStatementSuccess: (draft, action) => {
453
+ const { accountId, selectedPeriod } = action.payload;
454
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseStatus = {
455
+ fetchState: 'Completed',
456
+ error: undefined,
457
+ };
458
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = false;
459
+ draft.statementProcessingFailed = false;
460
+ },
461
+ parseStatementFailure: (draft, action) => {
462
+ const { accountId, selectedPeriod } = action.payload;
463
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseStatus = {
464
+ fetchState: 'Error',
465
+ error: action.payload.error,
466
+ };
467
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = false;
468
+ draft.statementProcessingFailed = true;
469
+ },
470
+ reparseStatement: (draft, action) => {
471
+ const { accountId, selectedPeriod } = action.payload;
472
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
473
+ if (accountRecon != null) {
474
+ accountRecon.parsedStatementData = undefined;
475
+ accountRecon.reparseStatementStatus = {
476
+ fetchState: 'In-Progress',
477
+ error: undefined,
478
+ };
479
+ }
480
+ },
481
+ reparseStatementSuccess: (draft, action) => {
482
+ const { accountId, selectedPeriod } = action.payload;
483
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
484
+ fetchState: 'Completed',
485
+ error: undefined,
486
+ };
487
+ draft.statementProcessingFailed = false;
488
+ },
489
+ reparseStatementFailure: (draft, action) => {
490
+ const { accountId, selectedPeriod } = action.payload;
491
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
492
+ fetchState: 'Error',
493
+ error: action.payload.error,
494
+ };
495
+ draft.statementProcessingFailed = true;
496
+ },
497
+ resetReparseStatementStatus: (draft, action) => {
498
+ const { accountId, selectedPeriod } = action.payload;
499
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
500
+ fetchState: 'Not-Started',
501
+ error: undefined,
502
+ };
503
+ },
504
+ updateParsedStatementData: (draft, action) => {
505
+ const { accountId, selectedPeriod, parsedStatementData } = action.payload;
506
+ draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].parsedStatementData =
507
+ parsedStatementData;
508
+ },
509
+ updateStatementUpdateLocalData: (draft, action) => {
510
+ const { accountId, selectedPeriod, statementUpdateLocalData } = action.payload;
511
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
512
+ if (accountRecon != null) {
513
+ if (accountRecon.localData == null) {
514
+ accountRecon.localData = {
515
+ statementUpdateLocalData,
516
+ };
517
+ }
518
+ else {
519
+ accountRecon.localData.statementUpdateLocalData =
520
+ statementUpdateLocalData;
521
+ }
522
+ }
523
+ },
524
+ submitStatementUpdate: (draft, action) => {
525
+ const { accountId, selectedPeriod } = action.payload;
526
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
527
+ if (accountRecon != null) {
528
+ accountRecon.statementUpdateStatus = {
529
+ fetchState: 'In-Progress',
530
+ error: undefined,
531
+ };
532
+ // Clear any stale date conflict from a previous attempt.
533
+ accountRecon.statementDateConflict = null;
534
+ }
535
+ },
536
+ submitStatementUpdateSuccess: (draft, action) => {
537
+ const { accountId, selectedPeriod } = action.payload;
538
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
539
+ if (accountRecon != null) {
540
+ accountRecon.statementUpdateStatus = {
541
+ fetchState: 'Completed',
542
+ error: undefined,
543
+ };
544
+ accountRecon.statementDateConflict = null;
545
+ if (accountRecon.localData != null) {
546
+ accountRecon.localData.statementUpdateLocalData = undefined;
547
+ }
548
+ }
549
+ },
550
+ submitStatementUpdateFailure: (draft, action) => {
551
+ const { accountId, selectedPeriod, dateConflict } = action.payload;
552
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
553
+ if (accountRecon != null) {
554
+ accountRecon.statementUpdateStatus = {
555
+ fetchState: 'Error',
556
+ error: action.payload.error,
557
+ };
558
+ accountRecon.statementDateConflict = dateConflict ?? null;
559
+ // Keep the local edits around when the failure is a recoverable date
560
+ // conflict so the user can re-upload / re-edit without losing changes.
561
+ if (dateConflict == null && accountRecon.localData != null) {
562
+ accountRecon.localData.statementUpdateLocalData = undefined;
563
+ }
564
+ }
565
+ },
566
+ clearStatementDateConflict: (draft, action) => {
567
+ const { accountId, selectedPeriod } = action.payload;
568
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
569
+ if (accountRecon != null) {
570
+ accountRecon.statementDateConflict = null;
571
+ }
572
+ },
422
573
  updateAccountReconciliationLocalData: (draft, action) => {
423
574
  const { accountId, selectedPeriod, localData } = action.payload;
424
575
  const oldLocalData = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData;
@@ -524,10 +675,10 @@ const expenseAutomationReconciliationView = createSlice({
524
675
  },
525
676
  });
526
677
  // Export actions
527
- export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
678
+ export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateStatementProcessingFailed, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateStatementUpdateLocalData, submitStatementUpdate, submitStatementUpdateSuccess, submitStatementUpdateFailure, clearStatementDateConflict, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
528
679
  // Export reducer
529
680
  export default expenseAutomationReconciliationView.reducer;
530
- function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts) {
681
+ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts, summary) {
531
682
  draft.excludedAccountIDs = excludedAccounts.map((ea) => ea.account_id);
532
683
  draft.excludedAccountExclusionInfo = {};
533
684
  excludedAccounts.forEach((ea) => {
@@ -556,6 +707,7 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
556
707
  : undefined,
557
708
  };
558
709
  });
710
+ const oldReconciliationByAccountID = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID ?? {};
559
711
  draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)] = {
560
712
  accountIDs: [],
561
713
  reconciliationByAccountID: {},
@@ -579,6 +731,7 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
579
731
  paymentAccountId: account?.payment_account_id ?? undefined,
580
732
  };
581
733
  }
734
+ const oldRecord = oldReconciliationByAccountID[reconciliation.account_id];
582
735
  accountReconciliationRecords.reconciliationByAccountID[reconciliation.account_id] = {
583
736
  accountId: reconciliation.account_id,
584
737
  reconciliationId: reconciliation.reconciliation_id ?? undefined,
@@ -588,14 +741,25 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
588
741
  statementUploadStatus: { fetchState: 'Not-Started', error: undefined },
589
742
  statementUpdateStatus: { fetchState: 'Not-Started', error: undefined },
590
743
  statementParseInProgress: reconciliation.bank_status.code === 'parsing',
744
+ statementParseStatus: oldRecord?.statementParseStatus ?? {
745
+ fetchState: 'Not-Started',
746
+ error: undefined,
747
+ },
748
+ reparseStatementStatus: oldRecord?.reparseStatementStatus ?? {
749
+ fetchState: 'Not-Started',
750
+ error: undefined,
751
+ },
752
+ statementDateConflict: oldRecord?.statementDateConflict ?? null,
591
753
  localData: {
754
+ ...oldRecord?.localData,
592
755
  accountSource: account?.reconciliation_source != null
593
756
  ? toReconciliationAccountSource(account.reconciliation_source)
594
- : undefined,
757
+ : oldRecord?.localData?.accountSource,
595
758
  },
596
759
  accountDetectionReason: account?.detection_info != null && account.detection_reason != null
597
760
  ? account.detection_reason
598
761
  : undefined,
762
+ parsedStatementData: oldRecord?.parsedStatementData,
599
763
  };
600
764
  accountReconciliationRecords.accountIDs.push(reconciliation.account_id);
601
765
  });
@@ -609,6 +773,9 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
609
773
  draft.fetchState = 'Completed';
610
774
  draft.error = undefined;
611
775
  }
776
+ if (summary !== undefined) {
777
+ draft.summary = toReconciliationViewSummary(summary);
778
+ }
612
779
  }
613
780
  function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accountId, reconciliationData, refreshViewInBackground) {
614
781
  const oldRecord = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId];
@@ -676,6 +843,9 @@ const updateReconciliationByAccountIDOnIncludeAccount = (draft, accountId, recon
676
843
  statementUploadStatus: { fetchState: 'Not-Started', error: undefined },
677
844
  statementUpdateStatus: { fetchState: 'Not-Started', error: undefined },
678
845
  statementParseInProgress: reconciliation.bank_status.code === 'parsing',
846
+ statementParseStatus: { fetchState: 'Not-Started', error: undefined },
847
+ reparseStatementStatus: { fetchState: 'Not-Started', error: undefined },
848
+ statementDateConflict: null,
679
849
  localData: {},
680
850
  accountDetectionReason: undefined,
681
851
  };
@@ -8,7 +8,7 @@ import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
8
8
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
9
9
  export function getExpenseAutomationFluxAnalysisView(state) {
10
10
  const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
11
- const { fetchState, error, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
11
+ const { fetchState, error, lastRefreshSuccessTime, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
12
12
  const fetchStateAndError = {
13
13
  fetchState,
14
14
  error,
@@ -110,6 +110,7 @@ export function getExpenseAutomationFluxAnalysisView(state) {
110
110
  refreshStatus,
111
111
  currency,
112
112
  completionStatus,
113
+ lastRefreshSuccessTime,
113
114
  };
114
115
  }
115
116
  // Helper function to transform operating expense to vendor view
@@ -43,6 +43,17 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
43
43
  error: undefined,
44
44
  })
45
45
  : { fetchState: 'Not-Started', error: undefined };
46
+ const monthEndChecksForPeriod = selectedPeriod != null
47
+ ? monthEndCloseChecksState.monthEndCloseChecksByTenantId[currentTenant.tenantId]?.[toMonthYearPeriodId(selectedPeriod)]
48
+ : undefined;
49
+ const reconCheckTimeSavedHours = monthEndChecksForPeriod?.monthEndCloseCheckList?.find((check) => check.id === 'reconciliation')?.progressJson?.timeSavedHours;
50
+ const summaryWithTimeSaved = reconciliationViewState.summary != null
51
+ ? {
52
+ ...reconciliationViewState.summary,
53
+ timeSavedHours: reconCheckTimeSavedHours ??
54
+ reconciliationViewState.summary.timeSavedHours,
55
+ }
56
+ : undefined;
46
57
  if (accountReconForMonthYearPeriod == null) {
47
58
  return {
48
59
  bankAccounts: [],
@@ -66,6 +77,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
66
77
  selectedTab: reconciliationViewState.selectedTab,
67
78
  monthYearPeriod: selectedPeriod,
68
79
  selectedAccountId: reconciliationViewState.selectedAccountId,
80
+ statementProcessingFailed: reconciliationViewState.statementProcessingFailed,
69
81
  statementUploadChosen: reconciliationViewState.statementUploadChosen,
70
82
  accountReconciliationsByAccountID: {},
71
83
  reconciliationTabsState: initialReconciliationTabsState,
@@ -115,6 +127,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
115
127
  excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
116
128
  includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
117
129
  excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
130
+ summary: summaryWithTimeSaved,
118
131
  };
119
132
  }
120
133
  const allAccountIDs = accountReconForMonthYearPeriod.accountIDs;
@@ -239,6 +252,12 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
239
252
  .refreshStatus,
240
253
  statementDeleteStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
241
254
  .statementDeleteStatus,
255
+ statementParseStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
256
+ .statementParseStatus,
257
+ reparseStatementStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
258
+ .reparseStatementStatus,
259
+ statementDateConflict: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
260
+ .statementDateConflict,
242
261
  statementUpdateStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
243
262
  .statementUpdateStatus,
244
263
  statementUploadStatus: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
@@ -247,6 +266,8 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
247
266
  .localData,
248
267
  statementParseInProgress: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
249
268
  .statementParseInProgress,
269
+ parsedStatementData: accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
270
+ .parsedStatementData,
250
271
  transactionFetchState: reduceAnyFetchState([
251
272
  accountReconForMonthYearPeriod.reconciliationByAccountID[accountID]
252
273
  .transactionFetchState,
@@ -315,6 +336,9 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
315
336
  statementUpdateStatus: { fetchState: 'Not-Started' },
316
337
  statementUploadStatus: { fetchState: 'Not-Started' },
317
338
  statementDeleteStatus: { fetchState: 'Not-Started' },
339
+ statementParseStatus: { fetchState: 'Not-Started' },
340
+ reparseStatementStatus: { fetchState: 'Not-Started' },
341
+ statementDateConflict: null,
318
342
  localData: {},
319
343
  connectionInProgress: false,
320
344
  statementParseInProgress: false,
@@ -403,6 +427,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
403
427
  refreshStatus: reconciliationViewState.refreshStatus,
404
428
  selectedTab: reconciliationViewState.selectedTab,
405
429
  selectedDrawerAccountId: reconciliationViewState.selectedDrawerAccountId,
430
+ statementProcessingFailed: reconciliationViewState.statementProcessingFailed,
406
431
  statementUploadChosen: reconciliationViewState.statementUploadChosen,
407
432
  monthYearPeriod: selectedPeriod,
408
433
  accountReconciliationBySectionID,
@@ -423,8 +448,10 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
423
448
  excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
424
449
  includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
425
450
  excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
451
+ summary: summaryWithTimeSaved,
426
452
  };
427
453
  });
454
+ export const getReparseStatementStatusByAccountId = (state, accountId) => getExpenseAutomationReconciliationView(state).accountReconciliationsByAccountID[accountId]?.reparseStatementStatus;
428
455
  export const isAccountReconReport = (reportId) => {
429
456
  return reportId.endsWith('reconciliation');
430
457
  };
@@ -1,4 +1,33 @@
1
1
  import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
+ export function toReconciliationViewSummary(payload) {
3
+ return {
4
+ accounts: {
5
+ done: payload.accounts.done,
6
+ failed: payload.accounts.failed,
7
+ inProgress: payload.accounts.in_progress,
8
+ total: payload.accounts.total,
9
+ },
10
+ accountsToConnectCount: payload.accounts_to_connect_count,
11
+ autoMatched: {
12
+ matchedTxns: payload.auto_matched.matched_txns,
13
+ totalTxns: payload.auto_matched.total_txns,
14
+ },
15
+ needsReview: {
16
+ accountCount: payload.needs_review.account_count,
17
+ txnCount: payload.needs_review.txn_count,
18
+ },
19
+ timeSavedHours: 0,
20
+ timeSavedPercentage: payload.time_saved_percentage,
21
+ progressBar: payload.progress_bar != null
22
+ ? {
23
+ aiPercentageShare: payload.progress_bar.ai_percentage_share,
24
+ completePercentage: payload.progress_bar.complete_percentage,
25
+ humanPercentageShare: payload.progress_bar.human_percentage_share,
26
+ remainingPercentage: payload.progress_bar.remaining_percentage,
27
+ }
28
+ : undefined,
29
+ };
30
+ }
2
31
  export const RECONCILE_ACTIONS = [
3
32
  'reconcile',
4
33
  'save_reconcile_for_later',
@@ -22,6 +22,10 @@ export const initialState = {
22
22
  error: undefined,
23
23
  },
24
24
  },
25
+ refreshStatus: {
26
+ fetchState: 'Not-Started',
27
+ error: undefined,
28
+ },
25
29
  summaryFetchState: {
26
30
  fetchState: 'Not-Started',
27
31
  error: undefined,
@@ -259,12 +263,32 @@ const opexByVendor = createSlice({
259
263
  [timeframe]: [],
260
264
  };
261
265
  },
266
+ refreshOpExByVendorReport(draft) {
267
+ draft.refreshStatus = { fetchState: 'In-Progress', error: undefined };
268
+ },
269
+ refreshOpExByVendorReportSuccess(draft, action) {
270
+ draft.refreshStatus = { fetchState: 'Completed', error: undefined };
271
+ if (action.payload.lastRefreshSuccessTime != null) {
272
+ draft.lastRefreshSuccessTime = action.payload.lastRefreshSuccessTime;
273
+ }
274
+ },
275
+ refreshOpExByVendorReportFailure: {
276
+ prepare(error) {
277
+ return { payload: { error } };
278
+ },
279
+ reducer(draft, action) {
280
+ draft.refreshStatus = {
281
+ fetchState: 'Error',
282
+ error: action.payload.error,
283
+ };
284
+ },
285
+ },
262
286
  clearOpExByVendor(draft) {
263
287
  Object.assign(draft, initialState);
264
288
  },
265
289
  },
266
290
  });
267
- export const { fetchOpExByVendor, updateOpExByVendorReportGenerated, fetchOpExByVendorReportForTimeframe, updateOpExByVendorReportFailureForTimeframe, updateOpExByVendorReportSuccessForTimeframe, fetchOpExByVendorReportSummary, updateOpExByVendorReportSummaryFailure, updateOpExByVendorReportSummarySuccess, updateOpExByVendorTimeFrame, updateOpExByVendorUIState, clearOpExByVendor, updateOpExByVendorAdditionalBalancesSelection, updateOpExByVendorSort, updateOpExByVendorSortOrSearchInProgress, updateOpExByVendorPageFetchInProgress, updateOpExByVendorDownloadState, clearOpExByVendorSearch, updateOpExByVendorPageLimit, updateOpExByVendorSearchString, } = opexByVendor.actions;
291
+ export const { fetchOpExByVendor, updateOpExByVendorReportGenerated, fetchOpExByVendorReportForTimeframe, updateOpExByVendorReportFailureForTimeframe, updateOpExByVendorReportSuccessForTimeframe, fetchOpExByVendorReportSummary, updateOpExByVendorReportSummaryFailure, updateOpExByVendorReportSummarySuccess, updateOpExByVendorTimeFrame, updateOpExByVendorUIState, clearOpExByVendor, updateOpExByVendorAdditionalBalancesSelection, updateOpExByVendorSort, updateOpExByVendorSortOrSearchInProgress, updateOpExByVendorPageFetchInProgress, updateOpExByVendorDownloadState, clearOpExByVendorSearch, updateOpExByVendorPageLimit, updateOpExByVendorSearchString, refreshOpExByVendorReport, refreshOpExByVendorReportSuccess, refreshOpExByVendorReportFailure, } = opexByVendor.actions;
268
292
  export default opexByVendor.reducer;
269
293
  const doUpdateOpexByVendorReport = (draft, timeframe, reportPayload, queryProps) => {
270
294
  if (reportPayload.status.is_report_generated == null) {
@@ -317,10 +341,9 @@ const doUpdateOpexByVendorReportSummary = (draft, reportPayload) => {
317
341
  const report = mapReportPayloadToReport(reportPayload);
318
342
  draft.firstMonthOfFY = report.firstMonthOfFY;
319
343
  draft.bookCloseDate = report.bookCloseDate;
320
- draft.lastRefreshSuccessTime =
321
- reportPayload.status.last_refresh_success_time != null
322
- ? date(reportPayload.status.last_refresh_success_time)
323
- : undefined;
344
+ if (reportPayload.status.last_refresh_success_time != null) {
345
+ draft.lastRefreshSuccessTime = date(reportPayload.status.last_refresh_success_time);
346
+ }
324
347
  draft.totalOpexByVendor = combineCOABalanceGrouped(mapCOABalanceGroupedPayloadV2ToCOABalanceGrouped(reportPayload.operating_expenses, reportPayload.currency, 'month'), mapCOABalanceGroupedPayloadV2ToCOABalanceGrouped(reportPayload.operating_expenses, reportPayload.currency, 'quarter'));
325
348
  draft.summaryOpexByVendorKey = mapVendorSummaryBalances(reportPayload.operating_expenses, reportPayload.currency);
326
349
  }
@@ -67,6 +67,7 @@ export const getOpExByVendorReport = createSelector((state) => state.opExByVendo
67
67
  filter,
68
68
  isReportGenerated: opExByVendorState.opExByVendorReportGenerated,
69
69
  lastRefreshSuccessTime: opExByVendorState.lastRefreshSuccessTime,
70
+ refreshStatus: opExByVendorState.refreshStatus,
70
71
  opexBalances,
71
72
  summaryBalances,
72
73
  allTimeframeTicks,
@@ -0,0 +1,21 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus } from '../../responsePayload';
4
+ import { date } from '../../zeniDayJS';
5
+ import { refreshOpExByVendorReport, refreshOpExByVendorReportFailure, refreshOpExByVendorReportSuccess, } from './opExByVendorReducer';
6
+ export const refreshOpExByVendorReportEpic = (actions$, _state, zeniAPI) => actions$.pipe(filter(refreshOpExByVendorReport.match), switchMap(() => {
7
+ return zeniAPI
8
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/reports/operating-expenses-by-vendor/refresh`)
9
+ .pipe(mergeMap((response) => {
10
+ if (response.status.code >= 200 && response.status.code < 300) {
11
+ const lastRefreshSuccessTime = response.status.last_refresh_success_time != null
12
+ ? date(response.status.last_refresh_success_time)
13
+ : undefined;
14
+ return of(refreshOpExByVendorReportSuccess({ lastRefreshSuccessTime }));
15
+ }
16
+ else {
17
+ return of(refreshOpExByVendorReportFailure(response.status));
18
+ }
19
+ }), catchError((error) => of(refreshOpExByVendorReportFailure(createZeniAPIStatus('Unexpected error', 'Refresh OpEx by Vendor REST API call errored out: ' +
20
+ JSON.stringify(error))))));
21
+ }));