@zeniai/client-epic-state 5.2.34 → 5.2.35-beta0MM

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 (94) hide show
  1. package/lib/entity/actualMatching/actualMatchingPayload.d.ts +25 -0
  2. package/lib/entity/actualMatching/actualMatchingPayload.js +43 -0
  3. package/lib/entity/actualMatching/actualMatchingReducer.d.ts +8 -0
  4. package/lib/entity/actualMatching/actualMatchingReducer.js +33 -0
  5. package/lib/entity/actualMatching/actualMatchingSelector.d.ts +3 -0
  6. package/lib/entity/actualMatching/actualMatchingSelector.js +6 -0
  7. package/lib/entity/actualMatching/actualMatchingState.d.ts +22 -0
  8. package/lib/entity/actualMatching/actualMatchingState.js +2 -0
  9. package/lib/entity/actualMatching/actualMatchingTypes.d.ts +1 -0
  10. package/lib/entity/actualMatching/actualMatchingTypes.js +2 -0
  11. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +29 -0
  12. package/lib/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  13. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +31 -0
  14. package/lib/epic.d.ts +8 -1
  15. package/lib/epic.js +14 -0
  16. package/lib/esm/entity/actualMatching/actualMatchingPayload.js +40 -0
  17. package/lib/esm/entity/actualMatching/actualMatchingReducer.js +30 -0
  18. package/lib/esm/entity/actualMatching/actualMatchingSelector.js +3 -0
  19. package/lib/esm/entity/actualMatching/actualMatchingState.js +1 -0
  20. package/lib/esm/entity/actualMatching/actualMatchingTypes.js +1 -0
  21. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +49 -0
  22. package/lib/esm/epic.js +14 -0
  23. package/lib/esm/index.js +6 -2
  24. package/lib/esm/reducer.js +6 -0
  25. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +46 -0
  26. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +35 -0
  27. package/lib/esm/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +7 -0
  28. package/lib/esm/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +52 -0
  29. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +44 -0
  30. package/lib/esm/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +73 -0
  31. package/lib/esm/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +52 -0
  32. package/lib/esm/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  33. package/lib/esm/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  34. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  35. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  36. package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
  37. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +68 -0
  38. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +364 -0
  39. package/lib/esm/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +1 -0
  40. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +281 -0
  41. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  42. package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +32 -0
  43. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  44. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  45. package/lib/index.d.ts +13 -5
  46. package/lib/index.js +78 -48
  47. package/lib/reducer.d.ts +2 -0
  48. package/lib/reducer.js +6 -0
  49. package/lib/rootStateTypes.d.ts +4 -0
  50. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.d.ts +9 -0
  51. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic.js +50 -0
  52. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.d.ts +12 -0
  53. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic.js +39 -0
  54. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.d.ts +5 -0
  55. package/lib/view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic.js +11 -0
  56. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.d.ts +8 -0
  57. package/lib/view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic.js +56 -0
  58. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.d.ts +8 -0
  59. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic.js +48 -0
  60. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.d.ts +8 -0
  61. package/lib/view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic.js +77 -0
  62. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.d.ts +8 -0
  63. package/lib/view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic.js +56 -0
  64. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.d.ts +2 -1
  65. package/lib/view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic.js +28 -11
  66. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.d.ts +2 -1
  67. package/lib/view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic.js +9 -1
  68. package/lib/view/expenseAutomationView/epics/jeSchedule/prefetchOtherJeSchedulesTabEpic.js +3 -1
  69. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +2 -1
  70. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +5 -0
  71. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +22 -7
  72. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +85 -0
  73. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +74 -0
  74. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +74 -0
  75. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +368 -0
  76. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +4 -4
  77. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +83 -0
  78. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.js +2 -0
  79. package/lib/view/expenseAutomationView/selectorTypes/expenseAutomationViewSelectorTypes.d.ts +2 -0
  80. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +29 -0
  81. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +296 -0
  82. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -0
  83. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +99 -0
  84. package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +38 -0
  85. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  86. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -1
  87. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.d.ts +1 -11
  88. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
  89. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +1 -2
  90. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +1 -2
  91. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +15 -1
  92. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
  93. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +1 -1
  94. package/package.json +1 -1
@@ -444,6 +444,52 @@ function toJEOneTimeAccrualAiSuggestion(payload, currencyCode) {
444
444
  : undefined,
445
445
  };
446
446
  }
447
+ function toJEOneTimeAccrualCleared(payload, currencyCode) {
448
+ if (payload == null) {
449
+ return undefined;
450
+ }
451
+ return {
452
+ matchedTransactionIntegrationId: payload.matched_transaction_integration_id ?? undefined,
453
+ matchedTransactionId: payload.matched_transaction_id ?? undefined,
454
+ matchedTransactionType: payload.matched_transaction_type ?? undefined,
455
+ matchedLineId: payload.matched_line_id ?? undefined,
456
+ consumedLineIds: payload.consumed_line_ids ?? undefined,
457
+ matchedAmount: payload.matched_amount != null
458
+ ? toOneTimeAccrualAmount(payload.matched_amount, currencyCode)
459
+ : undefined,
460
+ groupSum: payload.group_sum != null
461
+ ? toOneTimeAccrualAmount(payload.group_sum, currencyCode)
462
+ : undefined,
463
+ accrualIds: payload.accrual_ids ?? undefined,
464
+ reversedAt: payload.reversed_at != null ? date(payload.reversed_at) : undefined,
465
+ matchedTransactionDate: payload.matched_transaction_date != null
466
+ ? date(payload.matched_transaction_date)
467
+ : undefined,
468
+ matchTier: payload.match_tier ?? undefined,
469
+ matchShape: payload.match_shape ?? undefined,
470
+ matchedTransactionSyncToken: payload.matched_transaction_sync_token ?? undefined,
471
+ };
472
+ }
473
+ function toJEOneTimeAccrualMatchSuggestion(payload, currencyCode) {
474
+ if (payload == null) {
475
+ return undefined;
476
+ }
477
+ return {
478
+ resolution: payload.resolution ?? undefined,
479
+ matchTier: payload.match_tier ?? undefined,
480
+ matchedTransactionIntegrationId: payload.matched_transaction_integration_id ?? undefined,
481
+ matchedTransactionId: payload.matched_transaction_id ?? undefined,
482
+ matchedTransactionType: payload.matched_transaction_type ?? undefined,
483
+ matchedLineId: payload.matched_line_id ?? undefined,
484
+ matchedAmount: payload.matched_amount != null
485
+ ? toOneTimeAccrualAmount(payload.matched_amount, currencyCode)
486
+ : undefined,
487
+ matchedTransactionDate: payload.matched_transaction_date != null
488
+ ? date(payload.matched_transaction_date)
489
+ : undefined,
490
+ matchedTransactionSyncToken: payload.matched_transaction_sync_token ?? undefined,
491
+ };
492
+ }
447
493
  export function toJEOneTimeAccrual(payload) {
448
494
  return {
449
495
  accrualId: payload._id,
@@ -460,6 +506,8 @@ export function toJEOneTimeAccrual(payload) {
460
506
  profileSnapshot: toJEOneTimeAccrualProfileSnapshot(payload.profile_snapshot, payload.currency),
461
507
  isIgnored: payload.is_ignored === true,
462
508
  aiSuggestion: toJEOneTimeAccrualAiSuggestion(payload.ai_suggestion, payload.currency),
509
+ cleared: toJEOneTimeAccrualCleared(payload.cleared, payload.currency),
510
+ matchSuggestion: toJEOneTimeAccrualMatchSuggestion(payload.match_suggestion, payload.currency),
463
511
  // Exclusive by contract: a scheduled row reverses on expectedReversalDate and bills never
464
512
  // drive it, so the two never need reconciling. Defaulting to on_bill_match matches the
465
513
  // create path's default when the field is absent on an older document.
@@ -487,6 +535,7 @@ export function toJEOneTimeAccrual(payload) {
487
535
  transactionIntegrationId: payload.transaction_integration_id ?? undefined,
488
536
  reversalTransactionId: payload.reversal_transaction_id ?? undefined,
489
537
  createdBy: toJEOneTimeAccrualCreator(payload.created_by_user),
538
+ reversedBy: toJEOneTimeAccrualCreator(payload.reversed_by_user),
490
539
  };
491
540
  }
492
541
  // The accrual wire format carries a currency CODE but no symbol, so the symbol has to be derived.
package/lib/esm/epic.js CHANGED
@@ -196,6 +196,13 @@ import { updateCombinedStatementInfoEpic, } from './view/expenseAutomationView/e
196
196
  import { updateReconcileTabLocalDataEpic as updateExpenseAutomationReconciliationBalanceLocalDataEpic, } from './view/expenseAutomationView/epics/accountRecon/updateReconcileTabLocalDataEpic';
197
197
  import { updateStatementInfoEpic, } from './view/expenseAutomationView/epics/accountRecon/updateStatementInfoEpic';
198
198
  import { uploadAccountStatementEpic, } from './view/expenseAutomationView/epics/accountRecon/uploadAccountStatementEpic';
199
+ import { fetchActualMatchingEpic as fetchExpenseAutomationActualMatchingEpic, } from './view/expenseAutomationView/epics/actualMatching/fetchActualMatchingEpic';
200
+ import { fetchActualMatchingMatchEpic as fetchExpenseAutomationActualMatchingMatchEpic, } from './view/expenseAutomationView/epics/actualMatching/fetchActualMatchingMatchEpic';
201
+ import { fetchActualMatchingPageEpic as fetchExpenseAutomationActualMatchingPageEpic, } from './view/expenseAutomationView/epics/actualMatching/fetchActualMatchingPageEpic';
202
+ import { matchAndReverseAccrualsEpic, } from './view/expenseAutomationView/epics/actualMatching/matchAndReverseAccrualsEpic';
203
+ import { searchMatchAccrualsEpic, } from './view/expenseAutomationView/epics/actualMatching/searchMatchAccrualsEpic';
204
+ import { searchMatchTransactionsEpic, } from './view/expenseAutomationView/epics/actualMatching/searchMatchTransactionsEpic';
205
+ import { undoReversalAccrualsEpic, } from './view/expenseAutomationView/epics/actualMatching/undoReversalAccrualsEpic';
199
206
  import { fetchAllExpenseAutomationTabsEpic, } from './view/expenseAutomationView/epics/common/fetchAllExpenseAutomationTabsEpic';
200
207
  import { refreshExpenseAutomationCurrentTabEpic, } from './view/expenseAutomationView/epics/common/refreshExpenseAutomationCurrentTabEpic';
201
208
  import { fetchFluxAnalysisViewEpic as fetchExpenseAutomationFluxAnalysisViewEpic, } from './view/expenseAutomationView/epics/fluxAnalysis/fetchFluxAnalysisViewEpic';
@@ -1001,6 +1008,9 @@ const ALL_EPICS = [
1001
1008
  fetchEntityRecommendationsByTransactionIdEpic,
1002
1009
  fetchEntityRecommendationsForLineUpdateEpic,
1003
1010
  fetchExcludedResourcesEpic,
1011
+ fetchExpenseAutomationActualMatchingEpic,
1012
+ fetchExpenseAutomationActualMatchingMatchEpic,
1013
+ fetchExpenseAutomationActualMatchingPageEpic,
1004
1014
  fetchExpenseAutomationFluxAnalysisViewEpic,
1005
1015
  fetchExpenseAutomationInitializeTransactionCategorizationViewLocalDataEpic,
1006
1016
  fetchExpenseAutomationJeSchedulesEpic,
@@ -1295,6 +1305,7 @@ const ALL_EPICS = [
1295
1305
  lockChargeCardsEpic,
1296
1306
  markAsCompleteScheduleDetailEpic,
1297
1307
  markTransactionAsNotMiscategorizedEpic,
1308
+ matchAndReverseAccrualsEpic,
1298
1309
  notifyMeForFeatureEpic,
1299
1310
  oneTimeAccrualActionsEpic,
1300
1311
  parallelFetchAccountTransactionListEpic,
@@ -1403,6 +1414,8 @@ const ALL_EPICS = [
1403
1414
  saveVendorFirstReviewViewEpic,
1404
1415
  saveVendorsTabVendorEpic,
1405
1416
  scheduleTenantCreditScoreCronEpic,
1417
+ searchMatchAccrualsEpic,
1418
+ searchMatchTransactionsEpic,
1406
1419
  searchTransactionsForManualMatchEpic,
1407
1420
  searchTransactionsForNewScheduleEpic,
1408
1421
  seedAiCardCreationFormDraftEpic,
@@ -1442,6 +1455,7 @@ const ALL_EPICS = [
1442
1455
  treasuryTransferMoneyEpic,
1443
1456
  triggerAiAccountantJobEpic,
1444
1457
  triggerReviewTabRefetchEpic,
1458
+ undoReversalAccrualsEpic,
1445
1459
  unlinkPaymentAccountEpic,
1446
1460
  unlockChargeCardEpic,
1447
1461
  unlockChargeCardsEpic,
package/lib/esm/index.js CHANGED
@@ -188,6 +188,7 @@ import { toExpenseAutomationViewType, } from './view/expenseAutomationView/expen
188
188
  import { computeNewScheduleJeDetails } from './view/expenseAutomationView/helpers/newScheduleLocalDataHelper';
189
189
  import { isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardCreditType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, } from './view/expenseAutomationView/helpers/reconciliationHelpers';
190
190
  import { MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, } from './view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper';
191
+ import { clearActualMatchingView as clearExpenseAutomationActualMatchingView, clearMatchNewModal, closeMatchNewModal, fetchActualMatching as fetchExpenseAutomationActualMatching, fetchActualMatchingMatch, fetchActualMatchingPage as fetchExpenseAutomationActualMatchingPage, matchAndReverseAccruals, openMatchNewModal, searchMatchAccruals, searchMatchTransactions, undoReversalAccruals, updateActualMatchingUIState as updateExpenseAutomationActualMatchingUIState, } from './view/expenseAutomationView/reducers/actualMatchingViewReducer';
191
192
  import { clearExpenseAutomationFluxAnalysisView, fetchFluxAnalysisView, reviewFluxAnalysisView, updateFluxAnalysisViewPageMetaData, updateFluxAnalysisViewUIState, updateOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview, } from './view/expenseAutomationView/reducers/fluxAnalysisViewReducer';
192
193
  import { clearJeScheduleLocalData as clearExpenseAutomationJEScheduleLocalData, clearExpenseAutomationJESchedulesView, clearSearchTransactionsForNewSchedule as clearJeSearchTransactionsForNewSchedule, createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchJeSchedulesPage as fetchExpenseAutomationJESchedulesPage, fetchOneTimeAccrual, ignoreRecommendedJeSchedule as ignoreExpenseAutomationJESchedule, ignoreOneTimeAccrual, initializeAccountSettingsView as initializeJeAccountSettingsView, initializeNewSchedule as initializeJeNewSchedule, initializeJeScheduleLocalData, promoteOneTimeAccrual, removeJeOneTimeAccrualLocalData, removeJeScheduleTransactionKey, resetNewScheduleLocalData as resetJeNewScheduleLocalData, retryJeSchedule as retryExpenseAutomationJESchedule, revertJeSchedule, revertOneTimeAccrual, saveAccountSettings as saveJeAccountSettings, saveAccountSettingsLocalData as saveJeAccountSettingsLocalData, saveNewSchedule as saveJeNewSchedule, saveNewScheduleFailure as saveJeNewScheduleFailure, saveNewScheduleSuccess as saveJeNewScheduleSuccess, searchTransactionsForNewSchedule as searchJeTransactionsForNewSchedule, searchTransactionsForNewScheduleFailure as searchJeTransactionsForNewScheduleFailure, searchTransactionsForNewScheduleSuccess as searchJeTransactionsForNewScheduleSuccess, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJESchedulesUIState as updateExpenseAutomationJESchedulesUIState, updateJEScheduleTypeFilter, updateNewScheduleLocalData as updateJeNewScheduleLocalData, updateJeOneTimeAccrualLocalData, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, } from './view/expenseAutomationView/reducers/jeSchedulesViewReducer';
193
194
  import { acknowledgeBulkUploadConfirmMatchComplete, bulkUploadAutomatchingTimedOut, bulkUploadReceipts, bulkUploadReceiptsFailure, bulkUploadReceiptsSuccess, clearBulkUpload, clearBulkUploadBatchDetailsForScopeChange, clearManualSearchResults, clearMissingReceiptsTabNavigation, confirmBulkUploadMatch, confirmBulkUploadMatchFailure, confirmBulkUploadMatchSuccess, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsFailure, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatches, fetchBulkUploadBatchesFailure, fetchBulkUploadBatchesSuccess, fetchCompletedTransactions, fetchCompletedTransactionsFailure, fetchCompletedTransactionsSuccess, fetchMissingReceipts as fetchExpenseAutomationMissingReceipts, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, markBatchDetailRefreshAttempted, markMissingReceiptAsDone as markExpenseAutomationMissingReceiptAsDone, pusherBatchStatusUpdate, refreshBatchDetailsForBatchId, requestMissingReceiptsTabNavigation, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, searchTransactionsForManualMatch, searchTransactionsForManualMatchFailure, searchTransactionsForManualMatchSuccess, setBulkUploadCompletedSubTab, setBulkUploadResultsTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, storeBatchDetails, updateBulkUploadProgress, updateMissingReceiptUploadState as updateExpenseAutomationMissingReceiptUploadState, updateMissingReceiptsUIState as updateExpenseAutomationMissingReceiptsUIState, uploadMissingReceiptSuccess as uploadExpenseAutomationMissingReceiptSuccess, } from './view/expenseAutomationView/reducers/missingReceiptsViewReducer';
@@ -199,8 +200,9 @@ import { getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatemen
199
200
  import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, } from './view/expenseAutomationView/selectors/transactionCategorizationSelector';
200
201
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
201
202
  import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
203
+ import { MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toActualMatchingSortKey as toExpenseAutomationActualMatchingSortKey, toMatchAndReverseResultStatus, toUndoReversalResultStatus, } from './view/expenseAutomationView/types/actualMatchingViewState';
202
204
  import { DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab, } from './view/expenseAutomationView/types/completedSubTab';
203
- import { toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, } from './view/expenseAutomationView/types/jeSchedulesViewState';
205
+ import { ALL_JE_PAGE_TABS, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, toJEPageTab, } from './view/expenseAutomationView/types/jeSchedulesViewState';
204
206
  import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab, } from './view/expenseAutomationView/types/missingReceiptsViewState';
205
207
  import { toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey, } from './view/expenseAutomationView/types/missingReceiptsViewState';
206
208
  import { toReconciliationTabsType, } from './view/expenseAutomationView/types/reconciliationViewState';
@@ -489,7 +491,7 @@ export { stringToUnion, stringToUnionStrict };
489
491
  export { fetchMonthEndCloseChecks, fetchMonthClosePerformanceTrend, getMonthEndCloseChecksViewByTenantId, ALL_MONTH_END_CLOSE_CHECKS_FREQUENCY, };
490
492
  export {
491
493
  // Bulk Upload Types
492
- BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, toExpenseAutomationJEScheduleSortKey, toJEPageTab, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJEScheduleTypeFilter, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
494
+ BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, DEFAULT_COMPLETED_SUB_TAB, DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toCompletedSubTab, toMatchSource, toMissingReceiptsTab, ALL_JE_PAGE_TABS, MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, toExpenseAutomationJEScheduleSortKey, toExpenseAutomationActualMatchingSortKey, toJEPageTab, toMatchAndReverseResultStatus, toUndoReversalResultStatus, toggleJECreatedGroupCollapsed, toggleJEPendingGroupCollapsed, updateJEScheduleTypeFilter, getExpenseAutomationView, toExpenseAutomationMissingReceiptsSortKey, toExpenseAutomationTransactionsTabKey, toExpenseAutomationViewType, uploadExpenseAutomationMissingReceiptSuccess, markExpenseAutomationMissingReceiptAsDone, fetchAllExpenseAutomationTabs, refreshExpenseAutomationCurrentTab, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionGroup, fetchExpenseAutomationMissingReceipts,
493
495
  // Bulk Upload Actions
494
496
  bulkUploadReceipts, bulkUploadAutomatchingTimedOut, bulkUploadReceiptsSuccess, bulkUploadReceiptsFailure, restoreBulkUploadAutomatchingOnMount, restoreBulkUploadMatchingState, updateBulkUploadProgress, pusherBatchStatusUpdate, requestMissingReceiptsTabNavigation, clearMissingReceiptsTabNavigation, fetchBulkUploadBatchDetails, fetchBulkUploadBatchDetailsSuccess, fetchBulkUploadBatchDetailsFailure, storeBatchDetails, fetchMoreBatchDetails, fetchMoreBatchDetailsComplete, fetchMoreBatchDetailsFailure, fetchBulkUploadBatches, fetchBulkUploadBatchesSuccess, fetchBulkUploadBatchesFailure, clearBulkUploadBatchDetailsForScopeChange, markBatchDetailRefreshAttempted, refreshBatchDetailsForBatchId, confirmBulkUploadMatch, confirmBulkUploadMatchSuccess, confirmBulkUploadMatchFailure, setBulkUploadResultsTab, setBulkUploadCompletedSubTab, setBulkUploadSortConfig, setBulkUploadUploadedFileCount, clearBulkUpload, searchTransactionsForManualMatch, searchTransactionsForManualMatchSuccess, searchTransactionsForManualMatchFailure, clearManualSearchResults, acknowledgeBulkUploadConfirmMatchComplete, fetchCompletedTransactions, fetchCompletedTransactionsSuccess, fetchCompletedTransactionsFailure, fetchFluxAnalysisView, clearExpenseAutomationFluxAnalysisView, updateOperatingExpensesIdsForReview as updateFluxOperatingExpensesIdsForReview, updateSelectedSectionIdsForReview as updateFluxAnalysisSelectedSectionIdsForReview, reviewFluxAnalysisView, updateExpenseAutomationMissingReceiptUploadState, updateExpenseAutomationMissingReceiptsUIState, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, getExpenseAutomationFluxAnalysisView, updateCurrentSelectedView, updateCurrentSelectedPeriod, getExpenseAutomationTransactionView, getLastTransferEntryReplacement, updateFluxAnalysisViewUIState, updateFluxAnalysisViewPageMetaData, MAX_SELECTION_LIMIT, checkIfAllLineItemsAreCategoryClassFilled, getLineItemsByTransactionIdsFromLocalData, isAnyItemWithUncategorizedExpenseAccount, excludeAccountFromReconciliation, includeAccountInReconciliation, saveExpenseAutomationReconciliationDetail, updateExpenseAutomationReconcileTabListScrollState, updateExpenseAutomationReconReviewTabListSortState, updateExpenseAutomationReconcileTabListSortState, updateExpenseAutomationReconcileTabLocalData, updateExpenseAutomationAccountReconciliationSelectedTab, updateExpenseAutomationAccountReconciliationSelectedAccountId, getExpenseAutomationReconciliationView, getLedgerAccountIdsWithStatementOverrideWarning, getLedgerAccountsForCombinedStatementMapping, getReparseStatementStatusByAccountId, getUnavailableLedgerAccountIds, fetchReconciliationView, uploadAccountStatementIntoDocumentAI, updateExpenseAutomationReconListScrollPosition, setConnectionInProgressForAccountReconciliation, getAccountReconByAccountIdAndSelectedPeriod, toReconciliationTabsType, isAccountReconReport, updateExpenseAutomationReconReviewTabLocalData, updateExpenseAutomationSelectedDrawerAccountId, updateStatementProcessingFailed, saveExpenseAutomationReconciliationReview, updateExpenseAutomationAccountReconciliationLocalData, toReconciliationAccountSource, deleteAccountStatement, deleteCombinedStatement, uploadAccountStatement, parseCombinedStatement, parseStatement, parseStatementSuccess, parseStatementFailure, reparseStatement, reparseStatementSuccess, reparseStatementFailure, resetReparseStatementStatus, updateParsedStatementData, updateNodeCollapseState, updateStatementUploadChosen, submitCombinedStatementUpdate, submitStatementUpdate, clearStatementDateConflict, confirmStatementMapping, updateStatementUpdateLocalData, isReviewTransactionBankTransferType, isReviewTransactionBillPaymentType, isReviewTransactionCreditCardPaymentType, isReviewTransactionDepositType, isReviewTransactionExpenseType, isReviewTransactionCreditCardCreditType, setStatementParseInProgress, setStatementProcessingDismissedToBackground, updateStatementProcessingBackgroundCompletedSteps, };
495
497
  export { computeNewScheduleJeDetails, createOneTimeAccrual, createOneTimeAccrualFailure, createOneTimeAccrualSuccess, fetchOneTimeAccrual, getJeNewAccrualAccountsView, ignoreOneTimeAccrual, promoteOneTimeAccrual, revertJeSchedule, revertOneTimeAccrual, getJeNewScheduleSearchTransactionsView, getJeNewScheduleView, };
@@ -660,6 +662,7 @@ export { TIME_SERIES_DURATIONS, convertToTimeSeriesSelectionRange, toTimeSeriesD
660
662
  export { fetchApAging, getApAgingReport, updateApAgingUIState, };
661
663
  export { fetchApAgingDetail, getApAgingDetailForVendor, updateApAgingDetailUIState, };
662
664
  export { clearExpenseAutomationJEScheduleLocalData, clearExpenseAutomationJESchedulesView, clearJeSearchTransactionsForNewSchedule, fetchExpenseAutomationJESchedulesPage, ignoreExpenseAutomationJESchedule, initializeJeAccountSettingsView, initializeJeNewSchedule, initializeJeScheduleLocalData, removeJeScheduleTransactionKey, resetJeNewScheduleLocalData, retryExpenseAutomationJESchedule, saveJeNewSchedule, saveJeNewScheduleFailure, saveJeNewScheduleSuccess, searchJeTransactionsForNewSchedule, searchJeTransactionsForNewScheduleFailure, searchJeTransactionsForNewScheduleSuccess, updateExpenseAutomationJESchedulesUIState, updateJeNewScheduleLocalData, removeJeOneTimeAccrualLocalData, updateJeOneTimeAccrualLocalData, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, };
665
+ export { clearExpenseAutomationActualMatchingView, closeMatchNewModal, clearMatchNewModal, fetchExpenseAutomationActualMatching, fetchActualMatchingMatch, fetchExpenseAutomationActualMatchingPage, matchAndReverseAccruals, openMatchNewModal, searchMatchAccruals, searchMatchTransactions, undoReversalAccruals, updateExpenseAutomationActualMatchingUIState, };
663
666
  export { createNewSchedulesAccrued, deleteScheduleAccruedDetail, cancelScheduleAccruedJournalEntry, fetchScheduleAccruedDetails, fetchScheduleAccruedDetailsPage, resetJEAccruedLinkInLocalData, saveScheduleAccruedDetails, updateAmountsInScheduleAccruedDetail, updatedJEAccruedLinkWithRecommendedLocalData, updatedJELinkInLocalDataAccruedExpenses, fetchRecommendedTransactionRowIndex, clearSelectedJELinkRowIndex, updateLinkBillExpenseLocalData, updateScheduleAccruedDetailsLocalData, updateSelectedJEAccruedScheduleKey, resetSelectedJEAccruedScheduleKey, resetAccruedDetailNewScheduleState, };
664
667
  export { getJEScheduleTransactionKey, ALL_JE_SCHEDULE_IGNORE_REASONS, ALL_JE_SCHEDULE_REVERT_REASONS, ALL_ONE_TIME_ACCRUAL_IGNORE_REASONS, ALL_ONE_TIME_ACCRUAL_REVERT_REASONS, ALL_SCHEDULES_TYPES, getScheduleListReport, getAccruedScheduleListReport, fetchScheduleList, fetchAccruedScheduleList, fetchDownloadSchedules, fetchSchedulesAccount, updateScheduleListLocalData, getFetchStateForScheduleAccountList, toScheduleTypesType, toScheduleTypesTypeStrict, toScheduleListTabsFileTypeStrict, toScheduleSubTabType, updateScheduleListSubTab, updateScheduleListSearchText, updateScheduleListScrollState, updateScheduleListSortState, updateSelectedJEScheduleKey, fetchScheduleDetails, getScheduleDetailsView, getAccruedScheduleDetailsView, fetchScheduleDetailsPage, saveScheduleDetails, deleteScheduleDetail, createNewSchedules, updateScheduleDetailsLocalData, updateScheduleListDownloadState, updateAccruedJEScheduleAccruedByListKey, updatedSelectedJELinkRowIndex, getQBOUrlForLink, getThirdPartyIDFromQBOURL, updatedJELinkInLocalData, updateAmountsInScheduleDetail, resetJELinkInLocalData, updatedJELinkWithRecommendedLocalData, getFetchStateForScheduleListByType, getDefaultSelectedTimeframeForScheduleType, markAsCompleteScheduleDetail, resetMarkAsCompleteStatus, fetchVendorTabView, updateVendorTabViewTab, getVendorTabView, };
665
668
  export { toVendorFirstReviewViewColumnKeyType, getGlobalMerchantAutoCompleteResults, getVendorFirstReviewView, getVendorFirstReviewAttachmentView, fetchVendorFirstReviewView, fetchVendorFirstReviewAttachments, updateVendorFirstReviewViewScrollYOffset, resetVendorFirstReviewLocalData, updateVendorFirstReviewViewPageToken, clearRecentlySavedErroredVendorData, saveVendorFirstReviewView, updateVendorFirstReviewViewLocalData, updateVendorFirstReviewSortUiState, fetchGlobalMerchantAutoCompleteView, clearGlobalMerchantAutoCompleteResults, updateReviewVendorDetailLocalData, saveVendorDetailsView, getVendorDetailSelectorView, };
@@ -863,3 +866,4 @@ export { getInvoicingOnboardingGateView } from './view/invoicing/invoicingConfig
863
866
  // Accrued JE schedules are not a discriminated union member, so consumers need this guard to
864
867
  // narrow a JEScheduleRow before reading baseTransaction / recurringAmount.
865
868
  export { getExpenseAutomationJEOneTimeAccrualDetailView, getJEScheduleRowType, isAccruedScheduleRow, isAiAccountantSchedule, isExistingTabRow, isOneTimeAccrualRow, isRenderableOneTimeAccrual, isPendingReviewRow, } from './view/expenseAutomationView/selectors/jeSchedulesViewSelector';
869
+ export { getActualMatchingAmount, getActualMatchingReversalDate, parseActualMatchingMatchId, getExpenseAutomationActualMatchingMatchView, getExpenseAutomationActualMatchingView, isAutoReversedAccrual, isManuallyReversedAccrual, isPendingReviewAccrual, } from './view/expenseAutomationView/selectors/actualMatchingViewSelector';
@@ -42,6 +42,7 @@ import invoicingSubscription, { initialState as initialInvoicingSubscriptionStat
42
42
  import invoicingTransaction, { initialState as initialInvoicingTransactionState, } from './entity/invoicing/invoicingTransaction/invoicingTransactionReducer';
43
43
  import invoicingPlan, { initialState as initialInvoicingPlanState, } from './entity/invoicing/plan/planReducer';
44
44
  import invoicingProduct, { initialState as initialInvoicingProductState, } from './entity/invoicing/product/productReducer';
45
+ import actualMatching, { initialState as initialActualMatchingState, } from './entity/actualMatching/actualMatchingReducer';
45
46
  import jeSchedules, { initialState as initialJESchedulesState, } from './entity/jeSchedules/jeSchedulesReducer';
46
47
  import merchant, { initialState as initialMerchantState, } from './entity/merchant/merchantReducer';
47
48
  import monthEndCloseChecks, { initialState as initialMonthEndCloseChecksState, } from './entity/monthEndCloseChecks/monthEndCloseChecksReducer';
@@ -118,6 +119,7 @@ import creditAgentView, { initialState as initialCreditAgentViewState, } from '.
118
119
  import dashboard, { initialState as initialDashboardState, } from './view/dashboard/dashboardReducer';
119
120
  import dashboardLayout, { initialState as initialDashboardLayoutState, } from './view/dashboardLayout/dashboardLayoutReducer';
120
121
  import expenseAutomationView, { initialState as initialExpenseAutomationViewState, } from './view/expenseAutomationView/expenseAutomationViewReducer';
122
+ import expenseAutomationActualMatchingView, { initialState as initialExpenseAutomationActualMatchingViewState, } from './view/expenseAutomationView/reducers/actualMatchingViewReducer';
121
123
  import expenseAutomationFluxAnalysisView, { initialState as initialExpenseAutomationFluxAnalysisViewState, } from './view/expenseAutomationView/reducers/fluxAnalysisViewReducer';
122
124
  import expenseAutomationJESchedulesView, { initialState as initialExpenseAutomationJESchedulesViewState, } from './view/expenseAutomationView/reducers/jeSchedulesViewReducer';
123
125
  import expenseAutomationMissingReceiptsView, { initialState as initialExpenseAutomationMissingReceiptsViewState, } from './view/expenseAutomationView/reducers/missingReceiptsViewReducer';
@@ -279,6 +281,7 @@ const initialEntitiesState = {
279
281
  accountingSummaryState: initialAccountingSummaryState,
280
282
  accountReconState: initialAccountReconState,
281
283
  accountState: initialAccountState,
284
+ actualMatchingState: initialActualMatchingState,
282
285
  addressState: initialAddressState,
283
286
  aiAccountantCustomerState: initialAiAccountantCustomerState,
284
287
  aiCfoState: initialAiCfoState,
@@ -421,6 +424,7 @@ const initialViewsState = {
421
424
  entityAutoCompleteState: initialEntityAutoCompleteState,
422
425
  entityRecommendationState: initialEntityRecommendationState,
423
426
  expenseAutomationFluxAnalysisViewState: initialExpenseAutomationFluxAnalysisViewState,
427
+ expenseAutomationActualMatchingViewState: initialExpenseAutomationActualMatchingViewState,
424
428
  expenseAutomationJESchedulesViewState: initialExpenseAutomationJESchedulesViewState,
425
429
  expenseAutomationMissingReceiptsViewState: initialExpenseAutomationMissingReceiptsViewState,
426
430
  expenseAutomationReconciliationViewState: initialExpenseAutomationReconciliationViewState,
@@ -563,6 +567,7 @@ const entityReducers = {
563
567
  accountReconState: accountRecon,
564
568
  accountingSummaryState: accountingSummary,
565
569
  accountState: account,
570
+ actualMatchingState: actualMatching,
566
571
  addressState: address,
567
572
  aiAccountantCustomerState: aiAccountantCustomer,
568
573
  aiCfoState: aiCfo,
@@ -705,6 +710,7 @@ const viewReducers = {
705
710
  entityAutoCompleteState: entityAutoComplete,
706
711
  entityRecommendationState: recommendation,
707
712
  expenseAutomationFluxAnalysisViewState: expenseAutomationFluxAnalysisView,
713
+ expenseAutomationActualMatchingViewState: expenseAutomationActualMatchingView,
708
714
  expenseAutomationJESchedulesViewState: expenseAutomationJESchedulesView,
709
715
  expenseAutomationMissingReceiptsViewState: expenseAutomationMissingReceiptsView,
710
716
  expenseAutomationReconciliationViewState: expenseAutomationReconciliationView,
@@ -0,0 +1,46 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap, takeUntil, } from 'rxjs/operators';
3
+ import { updateActualMatchingMatches } from '../../../../entity/actualMatching/actualMatchingReducer';
4
+ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
6
+ import { clearAll } from '../../../../rootActions';
7
+ import { toServiceMonthFromPeriod, } from '../../payload/actualMatchingPayload';
8
+ import { fetchActualMatching, fetchActualMatchingFailure, fetchActualMatchingSuccess, } from '../../reducers/actualMatchingViewReducer';
9
+ export const fetchActualMatchingEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchActualMatching.match), switchMap((action) => {
10
+ const state = state$.value;
11
+ const { period, refreshViewInBackground } = action.payload;
12
+ const currentTenant = getCurrentTenant(state);
13
+ const selectedPeriod = state.expenseAutomationViewState
14
+ .selectedPeriodByTenantId[currentTenant?.tenantId ?? ''] ?? {
15
+ month: period.start.month,
16
+ year: period.start.year,
17
+ };
18
+ const serviceMonth = toServiceMonthFromPeriod(period);
19
+ return zeniAPI
20
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/actual-matching?service_month=${encodeURIComponent(serviceMonth)}`)
21
+ .pipe(mergeMap((response) => {
22
+ if (isSuccessResponse(response) && response.data != null) {
23
+ const matches = response.data.matches;
24
+ const updateActions = [];
25
+ if (matches.length > 0) {
26
+ updateActions.push(updateActualMatchingMatches(matches));
27
+ }
28
+ updateActions.push(fetchActualMatchingSuccess({
29
+ matchIds: matches.map((match) => match.match_id),
30
+ selectedPeriod,
31
+ refreshViewInBackground,
32
+ }));
33
+ return from(updateActions);
34
+ }
35
+ return of(fetchActualMatchingFailure({
36
+ status: response.status,
37
+ selectedPeriod,
38
+ refreshViewInBackground,
39
+ }));
40
+ }), catchError((error) => of(fetchActualMatchingFailure({
41
+ status: createZeniAPIStatus('Unexpected Error', 'fetch actual matching REST API call errored out' +
42
+ JSON.stringify(error)),
43
+ selectedPeriod,
44
+ refreshViewInBackground,
45
+ }))), takeUntil(actions$.pipe(filter(clearAll.match))));
46
+ }));
@@ -0,0 +1,35 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
+ import { updateActualMatchingMatches } from '../../../../entity/actualMatching/actualMatchingReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
+ import { clearAll } from '../../../../rootActions';
6
+ import { fetchActualMatchingMatch, fetchActualMatchingMatchFailure, fetchActualMatchingMatchSuccess, } from '../../reducers/actualMatchingViewReducer';
7
+ export const fetchActualMatchingMatchEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchActualMatchingMatch.match), mergeMap((action) => {
8
+ const { matchId, refreshViewInBackground } = action.payload;
9
+ return zeniAPI
10
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/actual-matching/${encodeURIComponent(matchId)}`)
11
+ .pipe(mergeMap((response) => {
12
+ if (isSuccessResponse(response) && response.data != null) {
13
+ return from([
14
+ updateActualMatchingMatches([response.data]),
15
+ fetchActualMatchingMatchSuccess({
16
+ matchId,
17
+ refreshViewInBackground,
18
+ }),
19
+ ]);
20
+ }
21
+ return from([
22
+ fetchActualMatchingMatchFailure({
23
+ matchId,
24
+ refreshViewInBackground,
25
+ status: response.status,
26
+ }),
27
+ ]);
28
+ }), catchError((error) => from([
29
+ fetchActualMatchingMatchFailure({
30
+ matchId,
31
+ refreshViewInBackground,
32
+ status: createZeniAPIStatus('Unexpected Error', `Fetch actual matching match REST API call errored out ${JSON.stringify(error)}`),
33
+ }),
34
+ ])), takeUntil(actions$.pipe(filter(clearAll.match))));
35
+ }));
@@ -0,0 +1,7 @@
1
+ import { of } from 'rxjs';
2
+ import { filter, mergeMap } from 'rxjs/operators';
3
+ import { fetchActualMatching, fetchActualMatchingPage, } from '../../reducers/actualMatchingViewReducer';
4
+ export const fetchActualMatchingPageEpic = (actions$) => actions$.pipe(filter(fetchActualMatchingPage.match), mergeMap((action) => {
5
+ const { period, refreshViewInBackground } = action.payload;
6
+ return of(fetchActualMatching(period, refreshViewInBackground));
7
+ }));
@@ -0,0 +1,52 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
+ import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
4
+ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
6
+ import { clearAll } from '../../../../rootActions';
7
+ import { toMatchAndReverseResult, } from '../../payload/actualMatchingPayload';
8
+ import { clearMatchNewModal, fetchActualMatching, matchAndReverseAccruals, matchAndReverseAccrualsFailure, matchAndReverseAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
9
+ function refreshActualMatchingList(state) {
10
+ const currentTenant = getCurrentTenant(state);
11
+ const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''];
12
+ if (selectedMonthYear == null) {
13
+ return [];
14
+ }
15
+ const period = convertToPeriod(selectedMonthYear);
16
+ const start = toAbsoluteDay(period.start);
17
+ const end = toAbsoluteDay(period.end);
18
+ if (start == null || end == null) {
19
+ return [];
20
+ }
21
+ return [fetchActualMatching({ start, end }, true)];
22
+ }
23
+ export const matchAndReverseAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(matchAndReverseAccruals.match), mergeMap((action) => {
24
+ const { transactionId, transactionIntegrationId, transactionType, lineId, accrualIds, transactionSyncToken, } = action.payload;
25
+ const body = {
26
+ transaction_id: transactionId,
27
+ transaction_integration_id: transactionIntegrationId,
28
+ transaction_type: transactionType,
29
+ line_id: lineId,
30
+ transaction_sync_token: transactionSyncToken,
31
+ accrual_ids: accrualIds,
32
+ };
33
+ return zeniAPI
34
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/match-and-reverse`, body)
35
+ .pipe(mergeMap((response) => {
36
+ if (isSuccessResponse(response) && response.data != null) {
37
+ const results = response.data.results.map(toMatchAndReverseResult);
38
+ const successActions = [
39
+ matchAndReverseAccrualsSuccess({ results }),
40
+ ];
41
+ const anyReversed = results.some((result) => result.status === 'reversed');
42
+ if (anyReversed) {
43
+ successActions.push(...refreshActualMatchingList(state$.value), clearMatchNewModal());
44
+ }
45
+ return from(successActions);
46
+ }
47
+ return of(matchAndReverseAccrualsFailure({ status: response.status }));
48
+ }), catchError((error) => of(matchAndReverseAccrualsFailure({
49
+ status: createZeniAPIStatus('Unexpected Error', 'Match and reverse accruals REST API call errored out' +
50
+ JSON.stringify(error)),
51
+ }))), takeUntil(actions$.pipe(filter(clearAll.match))));
52
+ }));
@@ -0,0 +1,44 @@
1
+ import { from, merge, of } from 'rxjs';
2
+ import { catchError, debounceTime, filter, mergeMap, switchMap, } from 'rxjs/operators';
3
+ import { updateJEOneTimeAccruals } from '../../../../entity/jeSchedules/jeSchedulesReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
+ import { searchMatchAccruals, searchMatchAccrualsFailure, searchMatchAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
6
+ import { MATCH_ACCRUAL_SEARCH_LIMIT, MATCH_SEARCH_DEBOUNCE_MS, } from '../../types/actualMatchingViewState';
7
+ export const searchMatchAccrualsEpic = (actions$, _state$, zeniAPI) => {
8
+ const searchActions$ = actions$.pipe(filter(searchMatchAccruals.match));
9
+ const pagination$ = searchActions$.pipe(filter((action) => action.payload.pageToken != null));
10
+ const newSearchDebounced$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null), debounceTime(MATCH_SEARCH_DEBOUNCE_MS));
11
+ return merge(pagination$, newSearchDebounced$).pipe(switchMap((action) => {
12
+ const { query, pageToken } = action.payload;
13
+ const offset = pageToken != null && pageToken.length > 0 ? Number(pageToken) : 0;
14
+ const searchText = encodeURIComponent(query);
15
+ const limit = MATCH_ACCRUAL_SEARCH_LIMIT;
16
+ return zeniAPI
17
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals?status=posted&reversal_policy=on_bill_match&search_text=${searchText}&limit=${limit}&offset=${offset}`)
18
+ .pipe(mergeMap((response) => {
19
+ if (isSuccessResponse(response) && response.data != null) {
20
+ const accruals = response.data.accruals;
21
+ const append = pageToken != null;
22
+ const nextOffset = offset + accruals.length;
23
+ const total = response.data.total ?? nextOffset;
24
+ const nextPageToken = nextOffset < total ? String(nextOffset) : null;
25
+ const actionsOut = [];
26
+ if (accruals.length > 0) {
27
+ actionsOut.push(updateJEOneTimeAccruals(accruals));
28
+ }
29
+ actionsOut.push(searchMatchAccrualsSuccess({
30
+ append,
31
+ nextPageToken,
32
+ results: accruals,
33
+ }));
34
+ return from(actionsOut);
35
+ }
36
+ return of(searchMatchAccrualsFailure({
37
+ error: response.status,
38
+ }));
39
+ }), catchError((error) => of(searchMatchAccrualsFailure({
40
+ error: createZeniAPIStatus('Unexpected Error', 'Search match accruals REST API call errored out' +
41
+ JSON.stringify(error)),
42
+ }))));
43
+ }));
44
+ };
@@ -0,0 +1,73 @@
1
+ import { from, merge, of } from 'rxjs';
2
+ import { catchError, debounceTime, filter, mergeMap, switchMap, } from 'rxjs/operators';
3
+ import { getActualMatchingMatchById } from '../../../../entity/actualMatching/actualMatchingSelector';
4
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
+ import { toActualMatchingTransactionSearchResult, } from '../../payload/actualMatchingPayload';
6
+ import { openMatchNewModal, searchMatchAccruals, searchMatchTransactions, searchMatchTransactionsFailure, searchMatchTransactionsSuccess, } from '../../reducers/actualMatchingViewReducer';
7
+ import { parseActualMatchingMatchId } from '../../selectors/actualMatchingViewSelector';
8
+ import { MATCH_SEARCH_DEBOUNCE_MS, MATCH_TRANSACTION_SEARCH_PAGE_SIZE, } from '../../types/actualMatchingViewState';
9
+ export const searchMatchTransactionsEpic = (actions$, state$, zeniAPI) => {
10
+ const openModal$ = actions$.pipe(filter(openMatchNewModal.match), mergeMap((action) => {
11
+ const matchId = action.payload.matchId;
12
+ if (matchId == null || matchId === '') {
13
+ return from([
14
+ searchMatchTransactions({ query: '' }),
15
+ searchMatchAccruals({ query: '' }),
16
+ ]);
17
+ }
18
+ const match = getActualMatchingMatchById(state$.value.actualMatchingState, matchId);
19
+ const parsed = parseActualMatchingMatchId(matchId);
20
+ const transactionType = match?.transactionType != null && match.transactionType !== ''
21
+ ? match.transactionType
22
+ : parsed?.transactionType;
23
+ const transactionIntegrationId = match?.transactionIntegrationId != null &&
24
+ match.transactionIntegrationId !== ''
25
+ ? match.transactionIntegrationId
26
+ : parsed?.transactionIntegrationId;
27
+ return from([
28
+ searchMatchTransactions({
29
+ query: '',
30
+ transactionType,
31
+ transactionIntegrationId,
32
+ }),
33
+ ]);
34
+ }));
35
+ const searchActions$ = actions$.pipe(filter(searchMatchTransactions.match));
36
+ const pagination$ = searchActions$.pipe(filter((action) => action.payload.pageToken != null));
37
+ const newSearchDebounced$ = searchActions$.pipe(filter((action) => action.payload.pageToken == null), debounceTime(MATCH_SEARCH_DEBOUNCE_MS));
38
+ const search$ = merge(pagination$, newSearchDebounced$).pipe(switchMap((action) => {
39
+ const { query, pageToken, transactionType, transactionIntegrationId } = action.payload;
40
+ const queryParam = {
41
+ search_text: query,
42
+ page_size: MATCH_TRANSACTION_SEARCH_PAGE_SIZE,
43
+ ...(pageToken != null ? { page_token: pageToken } : {}),
44
+ ...(transactionType != null && transactionType !== ''
45
+ ? { transaction_type: transactionType }
46
+ : {}),
47
+ ...(transactionIntegrationId != null && transactionIntegrationId !== ''
48
+ ? { transaction_integration_id: transactionIntegrationId }
49
+ : {}),
50
+ };
51
+ return zeniAPI
52
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/match-transaction-search?query=${encodeURIComponent(JSON.stringify(queryParam))}`)
53
+ .pipe(mergeMap((response) => {
54
+ if (isSuccessResponse(response) && response.data != null) {
55
+ const { transactions, next_page_token } = response.data;
56
+ const append = pageToken != null;
57
+ const results = transactions.map(toActualMatchingTransactionSearchResult);
58
+ return of(searchMatchTransactionsSuccess({
59
+ append,
60
+ nextPageToken: next_page_token ?? null,
61
+ results,
62
+ }));
63
+ }
64
+ return of(searchMatchTransactionsFailure({
65
+ error: response.status,
66
+ }));
67
+ }), catchError((error) => of(searchMatchTransactionsFailure({
68
+ error: createZeniAPIStatus('Unexpected Error', 'Search match transactions REST API call errored out' +
69
+ JSON.stringify(error)),
70
+ }))));
71
+ }));
72
+ return merge(openModal$, search$);
73
+ };
@@ -0,0 +1,52 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, takeUntil } from 'rxjs/operators';
3
+ import { convertToPeriod, toAbsoluteDay, } from '../../../../commonStateTypes/timePeriod';
4
+ import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
6
+ import { clearAll } from '../../../../rootActions';
7
+ import { toUndoReversalResult, } from '../../payload/actualMatchingPayload';
8
+ import { fetchActualMatching, fetchActualMatchingMatch, undoReversalAccruals, undoReversalAccrualsFailure, undoReversalAccrualsSuccess, } from '../../reducers/actualMatchingViewReducer';
9
+ function refreshActualMatchingList(state) {
10
+ const currentTenant = getCurrentTenant(state);
11
+ const selectedMonthYear = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant?.tenantId ?? ''];
12
+ if (selectedMonthYear == null) {
13
+ return [];
14
+ }
15
+ const period = convertToPeriod(selectedMonthYear);
16
+ const start = toAbsoluteDay(period.start);
17
+ const end = toAbsoluteDay(period.end);
18
+ if (start == null || end == null) {
19
+ return [];
20
+ }
21
+ return [fetchActualMatching({ start, end }, true)];
22
+ }
23
+ function refreshOpenMatchDetails(state) {
24
+ const detailState = state.expenseAutomationActualMatchingViewState.detailFetchStateByMatchId;
25
+ return Object.keys(detailState)
26
+ .filter((matchId) => detailState[matchId]?.fetchState !== 'Not-Started')
27
+ .map((matchId) => fetchActualMatchingMatch(matchId, true));
28
+ }
29
+ export const undoReversalAccrualsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(undoReversalAccruals.match), mergeMap((action) => {
30
+ const body = {
31
+ accrual_ids: action.payload.accrualIds,
32
+ };
33
+ return zeniAPI
34
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/accruals/undo-reversal`, body)
35
+ .pipe(mergeMap((response) => {
36
+ if (isSuccessResponse(response) && response.data != null) {
37
+ const results = response.data.results.map(toUndoReversalResult);
38
+ const successActions = [
39
+ undoReversalAccrualsSuccess({ results }),
40
+ ];
41
+ const anyUndone = results.some((result) => result.status === 'undone');
42
+ if (anyUndone) {
43
+ successActions.push(...refreshActualMatchingList(state$.value), ...refreshOpenMatchDetails(state$.value));
44
+ }
45
+ return from(successActions);
46
+ }
47
+ return of(undoReversalAccrualsFailure({ status: response.status }));
48
+ }), catchError((error) => of(undoReversalAccrualsFailure({
49
+ status: createZeniAPIStatus('Unexpected Error', 'Undo reversal accruals REST API call errored out' +
50
+ JSON.stringify(error)),
51
+ }))), takeUntil(actions$.pipe(filter(clearAll.match))));
52
+ }));
@@ -3,6 +3,7 @@ import { filter, switchMap } from 'rxjs/operators';
3
3
  import { convertToPeriod, toAbsoluteDay, toMonthYearPeriodId, } from '../../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
5
  import { fetchAllExpenseAutomationTabs } from '../../expenseAutomationViewReducer';
6
+ import { fetchActualMatchingPage } from '../../reducers/actualMatchingViewReducer';
6
7
  import { fetchFluxAnalysisView } from '../../reducers/fluxAnalysisViewReducer';
7
8
  import { fetchJeSchedulesPage } from '../../reducers/jeSchedulesViewReducer';
8
9
  import { fetchMissingReceipts } from '../../reducers/missingReceiptsViewReducer';
@@ -31,11 +32,14 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
31
32
  }
32
33
  if (cacheOverride === true) {
33
34
  const actions = [];
35
+ const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
34
36
  actions.push(fetchTransactionCategorizationView(selectedTransactionCategorizationTab, { start: timePeriodStart, end: timePeriodEnd }, cacheOverride, false, undefined, undefined, refreshViewInBackground, false), fetchMissingReceipts({ start: timePeriodStart, end: timePeriodEnd }, {
35
37
  amount: 75.0,
36
38
  currencyCode: 'USD',
37
39
  currencySymbol: '$',
38
- }, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null), fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
40
+ }, cacheOverride, refreshViewInBackground), fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null), selectedPageTab === 'actual_matching'
41
+ ? fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride)
42
+ : fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
39
43
  if (reconciliationEnabled) {
40
44
  actions.push(fetchReconciliation(selectedPeriod, undefined, cacheOverride, refreshViewInBackground));
41
45
  }
@@ -61,16 +65,29 @@ export const fetchAllExpenseAutomationTabsEpic = (actions$, state$) => actions$.
61
65
  fetchActions.push(fetchFluxAnalysisView(selectedPeriod, cacheOverride, refreshViewInBackground, null));
62
66
  }
63
67
  // The two JE tabs cache separately, so only the tab actually being shown decides whether a
64
- // fetch is still needed.
65
- const jeSchedulesPeriodTabKey = getJESchedulePeriodTabKey(state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab, monthYearPeriodId);
66
- if (state.expenseAutomationJESchedulesViewState.fetchState !==
67
- 'In-Progress' &&
68
- (!state.expenseAutomationJESchedulesViewState.hasValidState() ||
69
- state.expenseAutomationJESchedulesViewState
70
- .jeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null ||
71
- state.expenseAutomationJESchedulesViewState
72
- .failedJeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null)) {
73
- fetchActions.push(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
68
+ // fetch is still needed. Actual Matching is a third tab on the same page with its own
69
+ // endpoint and cache slot.
70
+ const selectedPageTab = state.expenseAutomationJESchedulesViewState.uiState.selectedPageTab;
71
+ if (selectedPageTab === 'actual_matching') {
72
+ const actualMatchingPeriodKeys = state.expenseAutomationActualMatchingViewState.matchIdsByPeriod[monthYearPeriodId];
73
+ if (state.expenseAutomationActualMatchingViewState.fetchState !==
74
+ 'In-Progress' &&
75
+ (!state.expenseAutomationActualMatchingViewState.hasValidState() ||
76
+ actualMatchingPeriodKeys == null)) {
77
+ fetchActions.push(fetchActualMatchingPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
78
+ }
79
+ }
80
+ else {
81
+ const jeSchedulesPeriodTabKey = getJESchedulePeriodTabKey(selectedPageTab, monthYearPeriodId);
82
+ if (state.expenseAutomationJESchedulesViewState.fetchState !==
83
+ 'In-Progress' &&
84
+ (!state.expenseAutomationJESchedulesViewState.hasValidState() ||
85
+ state.expenseAutomationJESchedulesViewState
86
+ .jeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null ||
87
+ state.expenseAutomationJESchedulesViewState
88
+ .failedJeScheduleTransactionKeysByPeriodAndTab[jeSchedulesPeriodTabKey] == null)) {
89
+ fetchActions.push(fetchJeSchedulesPage({ start: timePeriodStart, end: timePeriodEnd }, cacheOverride));
90
+ }
74
91
  }
75
92
  if (state.expenseAutomationReconciliationViewState.fetchState !==
76
93
  'In-Progress' &&