@zeniai/client-epic-state 5.2.41-beta5MM → 5.2.41-beta7MM

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 (196) hide show
  1. package/lib/entity/billPay/billTransaction/billTransactionReducer.d.ts +5 -1
  2. package/lib/entity/billPay/billTransaction/billTransactionReducer.js +17 -2
  3. package/lib/entity/invoicing/coupon/couponPayload.d.ts +8 -0
  4. package/lib/entity/invoicing/coupon/couponPayload.js +8 -0
  5. package/lib/entity/invoicing/coupon/couponState.d.ts +6 -0
  6. package/lib/entity/invoicing/dunningCase/dunningCaseTypes.d.ts +1 -1
  7. package/lib/entity/invoicing/plan/planSelector.d.ts +20 -0
  8. package/lib/entity/invoicing/plan/planSelector.js +42 -0
  9. package/lib/entity/invoicing/product/productPayload.d.ts +8 -1
  10. package/lib/entity/invoicing/product/productPayload.js +4 -1
  11. package/lib/entity/invoicing/product/productState.d.ts +16 -0
  12. package/lib/entity/jeSchedules/jeSchedulesReducer.d.ts +4 -1
  13. package/lib/entity/jeSchedules/jeSchedulesReducer.js +79 -5
  14. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  15. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  16. package/lib/entity/task/taskState.d.ts +1 -1
  17. package/lib/epic.d.ts +4 -1
  18. package/lib/epic.js +10 -4
  19. package/lib/esm/entity/billPay/billTransaction/billTransactionReducer.js +16 -1
  20. package/lib/esm/entity/invoicing/coupon/couponPayload.js +8 -0
  21. package/lib/esm/entity/invoicing/plan/planSelector.js +39 -0
  22. package/lib/esm/entity/invoicing/product/productPayload.js +4 -1
  23. package/lib/esm/entity/jeSchedules/jeSchedulesReducer.js +78 -4
  24. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  25. package/lib/esm/epic.js +10 -4
  26. package/lib/esm/index.js +8 -7
  27. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +3 -2
  28. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +39 -0
  29. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +14 -1
  30. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +10 -13
  31. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +38 -17
  32. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +17 -1
  33. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
  34. package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +6 -0
  35. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +74 -1
  36. package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
  37. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
  38. package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +11 -2
  39. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +49 -14
  40. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -11
  41. package/lib/esm/view/invoicing/createInvoice/createInvoiceSelector.js +28 -1
  42. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +67 -35
  43. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
  44. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +23 -4
  45. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.js +1 -7
  46. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +19 -5
  47. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +30 -7
  48. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +16 -1
  49. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
  50. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +69 -6
  51. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.js +22 -0
  52. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.js +22 -4
  53. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +18 -4
  54. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +29 -6
  55. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +28 -12
  56. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +37 -2
  57. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +43 -17
  58. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
  59. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +29 -6
  60. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +30 -14
  61. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +143 -8
  62. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
  63. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +44 -18
  64. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
  65. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +29 -8
  66. package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
  67. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +6 -6
  68. package/lib/esm/view/invoicing/invoicingFormDraft.js +78 -0
  69. package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +57 -9
  70. package/lib/esm/view/recommendation/recommendationPayload.js +3 -1
  71. package/lib/esm/view/recommendation/recommendationReducer.js +27 -7
  72. package/lib/esm/view/recommendation/recommendationSelector.js +1 -0
  73. package/lib/esm/view/recommendation/submitRecommendationFeedbackEpic.js +20 -8
  74. package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewReducer.js +87 -1
  75. package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +1 -0
  76. package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewState.js +4 -0
  77. package/lib/esm/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.js +97 -0
  78. package/lib/esm/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.js +85 -0
  79. package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewReducer.js +18 -1
  80. package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +3 -0
  81. package/lib/esm/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.js +95 -0
  82. package/lib/index.d.ts +9 -8
  83. package/lib/index.js +54 -48
  84. package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +3 -2
  85. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.d.ts +20 -0
  86. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +43 -0
  87. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.d.ts +2 -2
  88. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +13 -0
  89. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +8 -11
  90. package/lib/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +38 -17
  91. package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.d.ts +2 -2
  92. package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +17 -1
  93. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
  94. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  95. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +18 -0
  96. package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +18 -7
  97. package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +6 -0
  98. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +10 -3
  99. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +76 -3
  100. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
  101. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
  102. package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +3 -0
  103. package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +3 -0
  104. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +8 -4
  105. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +1 -0
  106. package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +12 -2
  107. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +49 -14
  108. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -10
  109. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +16 -0
  110. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +8 -5
  111. package/lib/view/invoicing/createInvoice/createInvoiceSelector.d.ts +7 -2
  112. package/lib/view/invoicing/createInvoice/createInvoiceSelector.js +28 -1
  113. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +46 -5
  114. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +69 -36
  115. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +3 -1
  116. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
  117. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +17 -0
  118. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +22 -3
  119. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewState.d.ts +2 -1
  120. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.d.ts +2 -2
  121. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.js +1 -7
  122. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +17 -3
  123. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.d.ts +10 -6
  124. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +29 -6
  125. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.d.ts +5 -1
  126. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +16 -1
  127. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.d.ts +3 -1
  128. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
  129. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +46 -0
  130. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +68 -5
  131. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.d.ts +21 -1
  132. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.js +24 -1
  133. package/lib/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.d.ts +9 -5
  134. package/lib/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.js +22 -4
  135. package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +18 -4
  136. package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.d.ts +10 -6
  137. package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +28 -5
  138. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +5 -1
  139. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +29 -13
  140. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +16 -7
  141. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +37 -2
  142. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +8 -1
  143. package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.d.ts +15 -10
  144. package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +42 -16
  145. package/lib/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
  146. package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.d.ts +10 -6
  147. package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +28 -5
  148. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.d.ts +5 -1
  149. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +31 -15
  150. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +79 -12
  151. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +145 -9
  152. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +8 -1
  153. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
  154. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.d.ts +15 -11
  155. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +42 -16
  156. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
  157. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.d.ts +10 -6
  158. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +28 -7
  159. package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.d.ts +10 -0
  160. package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
  161. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
  162. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -2
  163. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +6 -6
  164. package/lib/view/invoicing/invoicingFormDraft.d.ts +63 -0
  165. package/lib/view/invoicing/invoicingFormDraft.js +86 -0
  166. package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.d.ts +49 -0
  167. package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +59 -10
  168. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
  169. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +1 -1
  170. package/lib/view/recommendation/recommendationPayload.d.ts +1 -0
  171. package/lib/view/recommendation/recommendationPayload.js +5 -0
  172. package/lib/view/recommendation/recommendationReducer.d.ts +7 -1
  173. package/lib/view/recommendation/recommendationReducer.js +28 -8
  174. package/lib/view/recommendation/recommendationSelector.d.ts +2 -0
  175. package/lib/view/recommendation/recommendationSelector.js +3 -1
  176. package/lib/view/recommendation/recommendationState.d.ts +2 -1
  177. package/lib/view/recommendation/submitRecommendationFeedbackEpic.d.ts +2 -2
  178. package/lib/view/recommendation/submitRecommendationFeedbackEpic.js +18 -6
  179. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewPayload.d.ts +19 -0
  180. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewReducer.d.ts +10 -1
  181. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewReducer.js +88 -2
  182. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.d.ts +1 -0
  183. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +1 -0
  184. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewState.d.ts +7 -0
  185. package/lib/view/spendManagement/billPay/billDetailView/billDetailViewState.js +4 -0
  186. package/lib/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.d.ts +37 -0
  187. package/lib/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.js +104 -0
  188. package/lib/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.d.ts +24 -0
  189. package/lib/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.js +92 -0
  190. package/lib/view/spendManagement/billPay/editBillView/editBillViewReducer.d.ts +4 -1
  191. package/lib/view/spendManagement/billPay/editBillView/editBillViewReducer.js +19 -2
  192. package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.d.ts +1 -0
  193. package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +3 -0
  194. package/lib/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.d.ts +18 -0
  195. package/lib/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.js +102 -0
  196. package/package.json +2 -2
@@ -102,32 +102,27 @@ const expenseAutomationReconciliationView = createSlice({
102
102
  draft.selectedTab = 'review';
103
103
  draft.selectedAccountId = action.payload.accountId;
104
104
  }
105
- const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)];
106
- const { transactionFetchState } = accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId];
107
- if (transactionFetchState.fetchState !== 'Completed' ||
105
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)]?.reconciliationByAccountID[action.payload.accountId];
106
+ if (accountRecon == null) {
107
+ return;
108
+ }
109
+ if (accountRecon.transactionFetchState.fetchState !== 'Completed' ||
108
110
  action.payload.cacheOverride === true) {
109
- const data = accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId];
110
111
  if (action.payload.refreshViewInBackground === true) {
111
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId] = {
112
- ...data,
113
- refreshStatus: {
114
- fetchState: 'In-Progress',
115
- error: undefined,
116
- },
117
- accountId: action.payload.accountId,
118
- reconciliationId: undefined,
112
+ accountRecon.refreshStatus = {
113
+ fetchState: 'In-Progress',
114
+ error: undefined,
119
115
  };
116
+ accountRecon.accountId = action.payload.accountId;
117
+ accountRecon.reconciliationId = undefined;
120
118
  }
121
119
  else {
122
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId] = {
123
- ...data,
124
- transactionFetchState: {
125
- fetchState: 'In-Progress',
126
- error: undefined,
127
- },
128
- accountId: action.payload.accountId,
129
- reconciliationId: undefined,
120
+ accountRecon.transactionFetchState = {
121
+ fetchState: 'In-Progress',
122
+ error: undefined,
130
123
  };
124
+ accountRecon.accountId = action.payload.accountId;
125
+ accountRecon.reconciliationId = undefined;
131
126
  }
132
127
  }
133
128
  }
@@ -179,14 +174,17 @@ const expenseAutomationReconciliationView = createSlice({
179
174
  }
180
175
  }
181
176
  else {
182
- const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)];
177
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)]?.reconciliationByAccountID[action.payload.accountId];
178
+ if (accountRecon == null) {
179
+ return;
180
+ }
183
181
  if (action.payload.refreshViewInBackground === true) {
184
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId].refreshStatus.error = action.payload.error;
185
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId].refreshStatus.fetchState = 'Error';
182
+ accountRecon.refreshStatus.error = action.payload.error;
183
+ accountRecon.refreshStatus.fetchState = 'Error';
186
184
  }
187
185
  else {
188
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId].transactionFetchState.error = action.payload.error;
189
- accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId].transactionFetchState.fetchState = 'Error';
186
+ accountRecon.transactionFetchState.error = action.payload.error;
187
+ accountRecon.transactionFetchState.fetchState = 'Error';
190
188
  }
191
189
  }
192
190
  },
@@ -391,8 +389,11 @@ const expenseAutomationReconciliationView = createSlice({
391
389
  },
392
390
  setStatementParseInProgress: (draft, action) => {
393
391
  const { accountId, selectedPeriod, statementParseInProgress } = action.payload;
394
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress =
395
- statementParseInProgress;
392
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
393
+ if (accountRecon == null) {
394
+ return;
395
+ }
396
+ accountRecon.statementParseInProgress = statementParseInProgress;
396
397
  },
397
398
  setStatementProcessingDismissedToBackground: (draft, action) => {
398
399
  const { accountId, selectedPeriod, dismissedToBackground } = action.payload;
@@ -476,15 +477,23 @@ const expenseAutomationReconciliationView = createSlice({
476
477
  },
477
478
  uploadAccountStatementSuccess: (draft, action) => {
478
479
  const { accountId, selectedPeriod } = action.payload;
479
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementUploadStatus = {
480
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
481
+ if (accountRecon == null) {
482
+ return;
483
+ }
484
+ accountRecon.statementUploadStatus = {
480
485
  fetchState: 'Completed',
481
486
  error: undefined,
482
487
  };
483
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementParseInProgress = true;
488
+ accountRecon.statementParseInProgress = true;
484
489
  },
485
490
  uploadAccountStatementFailure: (draft, action) => {
486
491
  const { accountId, selectedPeriod } = action.payload;
487
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementUploadStatus = {
492
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
493
+ if (accountRecon == null) {
494
+ return;
495
+ }
496
+ accountRecon.statementUploadStatus = {
488
497
  fetchState: 'Error',
489
498
  error: action.payload.error,
490
499
  };
@@ -677,23 +686,34 @@ const expenseAutomationReconciliationView = createSlice({
677
686
  },
678
687
  reparseStatementFailure: (draft, action) => {
679
688
  const { accountId, selectedPeriod } = action.payload;
680
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
689
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
690
+ if (accountRecon == null) {
691
+ return;
692
+ }
693
+ accountRecon.reparseStatementStatus = {
681
694
  fetchState: 'Error',
682
695
  error: action.payload.error,
683
696
  };
684
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].statementProcessingFailed = true;
697
+ accountRecon.statementProcessingFailed = true;
685
698
  },
686
699
  resetReparseStatementStatus: (draft, action) => {
687
700
  const { accountId, selectedPeriod } = action.payload;
688
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].reparseStatementStatus = {
701
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
702
+ if (accountRecon == null) {
703
+ return;
704
+ }
705
+ accountRecon.reparseStatementStatus = {
689
706
  fetchState: 'Not-Started',
690
707
  error: undefined,
691
708
  };
692
709
  },
693
710
  updateParsedStatementData: (draft, action) => {
694
711
  const { accountId, selectedPeriod, parsedStatementData } = action.payload;
695
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].parsedStatementData =
696
- parsedStatementData;
712
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
713
+ if (accountRecon == null) {
714
+ return;
715
+ }
716
+ accountRecon.parsedStatementData = parsedStatementData;
697
717
  },
698
718
  updateStatementUpdateLocalData: (draft, action) => {
699
719
  const { accountId, selectedPeriod, statementUpdateLocalData, statementUploadId, } = action.payload;
@@ -819,17 +839,21 @@ const expenseAutomationReconciliationView = createSlice({
819
839
  },
820
840
  updateAccountReconciliationLocalData: (draft, action) => {
821
841
  const { accountId, selectedPeriod, localData } = action.payload;
822
- const oldLocalData = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData;
842
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
843
+ if (accountRecon == null) {
844
+ return;
845
+ }
846
+ const oldLocalData = accountRecon.localData;
823
847
  if (oldLocalData == null) {
824
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData = localData;
848
+ accountRecon.localData = localData;
825
849
  }
826
850
  else {
827
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData = {
851
+ accountRecon.localData = {
828
852
  ...oldLocalData,
829
853
  ...localData,
830
854
  };
831
855
  }
832
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId].localData = {
856
+ accountRecon.localData = {
833
857
  ...oldLocalData,
834
858
  ...localData,
835
859
  };
@@ -1119,7 +1143,10 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
1119
1143
  }
1120
1144
  }
1121
1145
  function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accountId, reconciliationData, refreshViewInBackground) {
1122
- const oldRecord = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId];
1146
+ const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
1147
+ if (accountRecon == null) {
1148
+ return;
1149
+ }
1123
1150
  const oldConnectionStatus = draft.accountConnectionStatusByAccountID[accountId];
1124
1151
  draft.accountConnectionStatusByAccountID[accountId] = {
1125
1152
  status: toBankStatusCodeType(reconciliationData.bank_status.code),
@@ -1129,21 +1156,17 @@ function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accoun
1129
1156
  : false,
1130
1157
  paymentAccountId: accounts.payment_account_id ?? undefined,
1131
1158
  };
1132
- const statementParseInProgress = resolveStatementParseInProgressAfterFetch(oldRecord, reconciliationData);
1159
+ const statementParseInProgress = resolveStatementParseInProgressAfterFetch(accountRecon, reconciliationData);
1160
+ accountRecon.reconciliationId =
1161
+ reconciliationData.reconciliation_id ?? undefined;
1162
+ accountRecon.statementParseInProgress = statementParseInProgress;
1133
1163
  if (refreshViewInBackground === true) {
1134
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId] = {
1135
- ...oldRecord,
1136
- reconciliationId: reconciliationData.reconciliation_id ?? undefined,
1137
- refreshStatus: { fetchState: 'Completed', error: undefined },
1138
- statementParseInProgress,
1139
- };
1164
+ accountRecon.refreshStatus = { fetchState: 'Completed', error: undefined };
1140
1165
  }
1141
1166
  else {
1142
- draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId] = {
1143
- ...oldRecord,
1144
- statementParseInProgress,
1145
- reconciliationId: reconciliationData.reconciliation_id ?? undefined,
1146
- transactionFetchState: { fetchState: 'Completed', error: undefined },
1167
+ accountRecon.transactionFetchState = {
1168
+ fetchState: 'Completed',
1169
+ error: undefined,
1147
1170
  };
1148
1171
  }
1149
1172
  }
@@ -1173,7 +1196,11 @@ const updateExcludedAccountExclusionInfo = (draft, account) => {
1173
1196
  };
1174
1197
  };
1175
1198
  const updateReconciliationByAccountIDOnIncludeAccount = (draft, accountId, reconciliation, monthYearPeriodId) => {
1176
- draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId].reconciliationByAccountID[accountId] = {
1199
+ const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId];
1200
+ if (accountReconciliationRecords == null) {
1201
+ return;
1202
+ }
1203
+ accountReconciliationRecords.reconciliationByAccountID[accountId] = {
1177
1204
  accountId,
1178
1205
  reconciliationId: reconciliation.reconciliation_id ?? undefined,
1179
1206
  transactionFetchState: { fetchState: 'Not-Started', error: undefined },
@@ -373,6 +373,16 @@ const expenseAutomationTransactionsView = createSlice({
373
373
  if (cached != null) {
374
374
  autoCat.uiState.pageToken = cached.pageToken;
375
375
  autoCat.uiState.totalCount = { ...cached.totalCount };
376
+ // Keep the stored badge in step with the restored sub-tab: the selector
377
+ // falls back to it for any period this sub-tab has not loaded. Merged,
378
+ // not replaced -- the snapshot only holds periods this sub-tab actually
379
+ // loaded, while the badge map also carries periods filled from a Review
380
+ // response's `other_tab_total_count`. Overwriting would drop those and
381
+ // leave the badge at 0 for any period this sub-tab never visited.
382
+ draft.parentTotalCountByTab.autoCategorized = {
383
+ ...draft.parentTotalCountByTab.autoCategorized,
384
+ ...cached.totalCount,
385
+ };
376
386
  autoCat.uiState.scrollPosition = cached.scrollPosition;
377
387
  autoCat.transactionIdsBySelectedPeriod = {
378
388
  ...cached.transactionIdsBySelectedPeriod,
@@ -227,6 +227,7 @@ function emptyKpiSummary() {
227
227
  actualsReceived: { count: 0, expectedCount: 0, vendorsPending: 0 },
228
228
  autoReversed: { count: 0, percent: 0, clearedAmount: 0 },
229
229
  pendingReview: { count: 0, amount: 0, estimatedMinutesToClear: 0 },
230
+ reversed: { count: 0 },
230
231
  variance: { percent: 0, averagePercentPerMatch: 0, netAmount: 0 },
231
232
  };
232
233
  }
@@ -282,6 +283,7 @@ export function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
282
283
  }
283
284
  const autoReversed = kpiRows.filter((row) => row.kind === 'auto_reversed');
284
285
  const pendingReview = kpiRows.filter((row) => row.kind === 'pending_review');
286
+ const reversed = kpiRows.filter((row) => isReversedMatchKind(row.kind));
285
287
  const receivedCount = kpiRows.length;
286
288
  const rowsWithActual = kpiRows.filter((row) => row.actualAmount?.amount != null);
287
289
  const accruedTotal = rowsWithActual.reduce((sum, row) => sum + (row.accruedAmount?.amount ?? row.estimatedAmount.amount), 0);
@@ -307,6 +309,9 @@ export function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
307
309
  amount: sumRowAmounts(pendingReview, displayCurrencyCode),
308
310
  estimatedMinutesToClear: pendingReview.length * ESTIMATED_MINUTES_PER_PENDING_MATCH,
309
311
  },
312
+ reversed: {
313
+ count: reversed.length,
314
+ },
310
315
  variance: {
311
316
  percent: accruedTotal === 0
312
317
  ? 0
@@ -328,6 +333,7 @@ function toActualMatchingMatchView(match) {
328
333
  : match.leftovers.map(toMatchModalAccrual),
329
334
  };
330
335
  }
336
+ const EMPTY_ACTUAL_MATCHING_ROWS = [];
331
337
  export function getExpenseAutomationActualMatchingMatchView(state, matchId) {
332
338
  const view = state.expenseAutomationActualMatchingViewState;
333
339
  const match = getActualMatchingMatchById(state.actualMatchingState, matchId);
@@ -348,6 +354,9 @@ export function getCloseMatchAfterIgnoreMatchId(state) {
348
354
  return state.expenseAutomationActualMatchingViewState
349
355
  .closeMatchAfterIgnoreMatchId;
350
356
  }
357
+ export function getActualMatchingMatchModalConfirmStatus(state) {
358
+ return state.expenseAutomationActualMatchingViewState.matchModal.confirmStatus;
359
+ }
351
360
  export function getExpenseAutomationActualMatchingView(state) {
352
361
  const { expenseAutomationActualMatchingViewState } = state;
353
362
  const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, ignoreStatusByMatchId, undoReversalStatusByMatchId, } = expenseAutomationActualMatchingViewState;
@@ -364,10 +373,10 @@ export function getExpenseAutomationActualMatchingView(state) {
364
373
  const includeReversed = uiState.statusFilter !== 'pending_review';
365
374
  const reversed = includeReversed
366
375
  ? sortActualMatchingRows(rows.filter((row) => isReversedMatchKind(row.kind)), uiState)
367
- : [];
376
+ : EMPTY_ACTUAL_MATCHING_ROWS;
368
377
  const pendingReview = includePendingReview
369
378
  ? sortActualMatchingRows(rows.filter((row) => row.kind === 'pending_review'), uiState)
370
- : [];
379
+ : EMPTY_ACTUAL_MATCHING_ROWS;
371
380
  const kpiSummary = buildActualMatchingKpiSummary(allRows, getTenantDisplayCurrency(state)?.currencyCode);
372
381
  const searchedAccruals = matchModal.accrualSearch.results
373
382
  .map((key) => getJEOneTimeAccrualByKey(key, state.jeSchedulesState))
@@ -210,7 +210,7 @@ export function getExpenseAutomationJESchedulesView(state) {
210
210
  const accruedSchedules = [];
211
211
  const oneTimeAccruals = [];
212
212
  const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
213
- const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJeScheduleTransactionKeysByPeriodAndTab, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
213
+ const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJePostings, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
214
214
  const accountSettingsView = getJEAccountSettingsView(state);
215
215
  const newScheduleView = newSchedule.selectedDetailScheduleType === 'fixed_assets' ||
216
216
  newSchedule.selectedDetailScheduleType === 'prepaid_expenses'
@@ -249,15 +249,11 @@ export function getExpenseAutomationJESchedulesView(state) {
249
249
  const jeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
250
250
  ? jeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
251
251
  : undefined;
252
- const failedJeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
253
- ? failedJeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
254
- : undefined;
255
252
  // Distinguishes "this tab has never been fetched for this period" from "fetched and genuinely
256
253
  // empty". Without it the page cannot tell a first visit from a real empty state, and renders an
257
254
  // empty table where it should render a skeleton.
258
255
  const hasLoadedForSelectedTab = jeScheduleTransactionKeysForSelectedTab != null;
259
256
  const jeScheduleTransactionKeys = jeScheduleTransactionKeysForSelectedTab ?? [];
260
- const failedJeScheduleTransactionKeys = failedJeScheduleTransactionKeysForSelectedTab ?? [];
261
257
  const jeScheduleAccruedKeys = (selectedPeriodTabKey != null
262
258
  ? jeScheduleAccruedKeysByPeriodAndTab[selectedPeriodTabKey]
263
259
  : undefined) ?? [];
@@ -280,24 +276,57 @@ export function getExpenseAutomationJESchedulesView(state) {
280
276
  accruedSchedules.push(accruedScheduleDetails);
281
277
  }
282
278
  });
283
- failedJeScheduleTransactionKeys.forEach((jeScheduleKey) => {
284
- const jeScheduleDetails = getJEScheduledTransactionByJEScheduleTransactionKey(jeScheduleKey, state);
285
- failedJeScheduledTransaction.push(jeScheduleDetails);
279
+ // Sourced from the tenant-wide bucket, not the per-period one: a failed posting belongs to no
280
+ // close month, and windowing it is what kept older failures off the only tab that can resolve
281
+ // them.
282
+ failedJePostings.jeScheduleTransactionKeys.forEach((jeScheduleKey) => {
283
+ // getJEScheduledTransactionByJEScheduleTransactionKey throws three different ways: it
284
+ // destructures the result of recordGet without a null check, and it raises explicitly for a
285
+ // missing vendor and for a missing base transaction. Catching rather than pre-checking each
286
+ // one keeps this correct if a fourth is added, and none of the three is recoverable here --
287
+ // the row cannot be drawn either way.
288
+ //
289
+ // This matters more for this bucket than anywhere else on the page. It is tenant-wide, so it
290
+ // names schedules the close-month list never loaded, and the group is defined by deleted
291
+ // vendors and deleted categories -- precisely the rows whose entities are most likely to be
292
+ // missing. Unguarded, one such key takes down the whole JE tab instead of dropping one row.
293
+ try {
294
+ failedJeScheduledTransaction.push(getJEScheduledTransactionByJEScheduleTransactionKey(jeScheduleKey, state));
295
+ }
296
+ catch {
297
+ // Intentionally swallowed: a failed posting we cannot resolve is one missing row, and the
298
+ // alternative is a blank page for every other row too.
299
+ }
286
300
  });
301
+ // What the endpoint last reported as failing. The entity store keeps every month a schedule
302
+ // has and an entry resolved by someone else keeps its old `error` array, so `error` alone would
303
+ // leave a Retry button on a posting that is no longer failing.
304
+ const failedScheduledJournalEntryIDs = new Set(failedJePostings.scheduledJournalEntryIDs);
287
305
  const { sortKey, sortOrder, selectedJETypeFilter } = uiState;
306
+ const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
307
+ getJEScheduleRowType(schedule) === selectedJETypeFilter;
288
308
  const unsortedResolveSchedules = [];
289
309
  failedJeScheduledTransaction.forEach((schedule) => {
290
- schedule.scheduledJournalEntry.forEach((journalEntry) => {
310
+ // Only the entries that actually carry an error. The schedule's entry array is shared state:
311
+ // opening a schedule's detail page or Quick View replaces it with every month the schedule
312
+ // has, posted ones included, so fanning out over all of them turned one failed posting into a
313
+ // row per month -- and a month that never failed has nothing to resolve, so it rendered with
314
+ // an empty action column.
315
+ //
316
+ // Intersected with the ids the endpoint actually returned, not just `error`: the entry array
317
+ // is a cache of every month, and an entry whose failure someone else resolved keeps its stale
318
+ // error array until something overwrites it. Only what the last fetch named is still failing.
319
+ schedule.scheduledJournalEntry
320
+ .filter((journalEntry) => journalEntry.error.length > 0 &&
321
+ failedScheduledJournalEntryIDs.has(journalEntry.scheduledJournalEntryID))
322
+ .forEach((journalEntry) => {
291
323
  unsortedResolveSchedules.push({
292
324
  ...schedule,
293
325
  scheduledJournalEntry: journalEntry,
294
326
  });
295
327
  });
296
328
  });
297
- const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules, sortKey, sortOrder);
298
- const validResolveForPending = unsortedResolveSchedules.filter((r) => jeScheduleLocalDataById[r.scheduledJournalEntry.scheduledJournalEntryID] != null);
299
- const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
300
- getJEScheduleRowType(schedule) === selectedJETypeFilter;
329
+ const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules.filter(matchesTypeFilter), sortKey, sortOrder);
301
330
  const isCreatedStatus = (schedule) => {
302
331
  // An accrual is "created" once it is not review work: posted, reversing, reversed, or in a
303
332
  // transient posting claim.
@@ -315,7 +344,6 @@ export function getExpenseAutomationJESchedulesView(state) {
315
344
  ];
316
345
  const pendingReviewSchedules = sortJEScheduledTransactions([
317
346
  ...allScheduleRows.filter((schedule) => isPendingReviewRow(schedule) && matchesTypeFilter(schedule)),
318
- ...validResolveForPending,
319
347
  ], sortKey, sortOrder);
320
348
  const createdSchedules = sortJEScheduledTransactions(allScheduleRows.filter((schedule) => isCreatedStatus(schedule) && matchesTypeFilter(schedule)), sortKey, sortOrder);
321
349
  // KPI summary — derived from unfiltered schedules so counts are always accurate
@@ -434,6 +462,13 @@ export function getExpenseAutomationJESchedulesView(state) {
434
462
  kpiSummary,
435
463
  pendingReviewSchedules,
436
464
  pendingReviewTotal,
465
+ failedPostings: resolveSchedules,
466
+ // Exposed so a consumer can tell "still loading" and "the lookup failed" from "nothing has
467
+ // failed". The bucket keeps its rows on failure precisely so an error can be shown beside
468
+ // them, which is only possible if the state travels with them.
469
+ failedPostingsFetchState: failedJePostings.fetchState,
470
+ // Deprecated alias of failedPostings. Still read by the section's footer-form effect and by
471
+ // app-ui analytics; remove once both are repointed.
437
472
  resolveSchedules: resolveSchedules,
438
473
  accountSettingsView,
439
474
  newScheduleView,
@@ -1,6 +1,6 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
2
  import omit from 'lodash/omit';
3
- import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
+ import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant, getIsAccountingProjectsEnabled, } from '../../../entity/tenant/tenantSelector';
5
5
  import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
6
6
  import { getSupportedTransactionsByIds } from '../../../entity/transaction/transactionSelector';
@@ -172,18 +172,35 @@ export function getExpenseAutomationTransactionView(state) {
172
172
  review: monthYearPeriodId != null ? totalCountByReview[monthYearPeriodId] : 0,
173
173
  autoCategorized: monthYearPeriodId != null ? totalCountByAutoCat[monthYearPeriodId] : 0,
174
174
  };
175
- // Parent-tab badge counts. Sourced from `parent_tab_total_count` in the
176
- // listing response and used exclusively by the navbar / tab strip badges.
177
- // Independent of which Completed sub-tab is active so the badge stays
178
- // stable across sub-tab switches.
175
+ // Tab badge counts, used exclusively by the navbar / tab strip badges. Both
176
+ // tabs are counted under the filters applied to the list, so a badge always
177
+ // equals the number of rows that tab shows.
178
+ //
179
+ // The ACTIVE tab prefers its own list count: the two are the same number (the
180
+ // backend's parent_tab_total_count mirrors total_count), but `uiState.totalCount`
181
+ // is restored by every cache path that skips a fetch -- switching back to an
182
+ // already-loaded period, or to a cached Completed sub-tab -- whereas the stored
183
+ // badge is only written when a response lands, so on those paths it would keep
184
+ // showing whatever was fetched last.
185
+ //
186
+ // The `in` check is load-bearing, not defensive: `totalCount` is a per-period
187
+ // map typed as `Record<MonthYearPeriodId, number>`, so indexing it is typed
188
+ // `number` but is `undefined` for any period the active (sub-)tab has not
189
+ // loaded -- the window between switching to a fresh sub-tab and its response
190
+ // landing. Falling back to the stored badge there keeps a real number in the
191
+ // label instead of blanking it.
179
192
  const parentTotalCountByTab = expenseAutomationTransactionsViewState.parentTotalCountByTab;
193
+ const storedBadgeByTab = (tab) => monthYearPeriodId != null
194
+ ? (parentTotalCountByTab[tab][monthYearPeriodId] ?? 0)
195
+ : 0;
196
+ const badgeForTab = (tab, listCountByPeriod) => selectedTransactionCategorizationTab === tab &&
197
+ monthYearPeriodId != null &&
198
+ monthYearPeriodId in listCountByPeriod
199
+ ? listCountByPeriod[monthYearPeriodId]
200
+ : storedBadgeByTab(tab);
180
201
  const parentTabTotalCountByTab = {
181
- review: monthYearPeriodId != null
182
- ? (parentTotalCountByTab.review[monthYearPeriodId] ?? 0)
183
- : 0,
184
- autoCategorized: monthYearPeriodId != null
185
- ? (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
186
- : 0,
202
+ review: badgeForTab('review', totalCountByReview),
203
+ autoCategorized: badgeForTab('autoCategorized', totalCountByAutoCat),
187
204
  };
188
205
  const fetchStateByTab = {
189
206
  review: {
@@ -1,8 +1,35 @@
1
1
  import { getAddressByAddressId } from '../../../entity/address/addressSelector';
2
+ import { invoicingPricePointDisplayAmount } from '../../../entity/invoicing/plan/planSelector';
2
3
  import { getInvoicingCatalogListView, getInvoicingCatalogPrices, } from '../invoicingCatalogListView/invoicingCatalogListViewSelector';
3
4
  import { invoicingFieldHelpForGroup } from '../invoicingConfigView/invoicingConfigViewSelector';
4
5
  import { getInvoicingCustomerListView } from '../invoicingCustomerListView/invoicingCustomerListViewSelector';
5
6
  import { getInvoicingSettings } from '../settingsView/settingsViewSelector';
7
+ /**
8
+ * Pricing models whose single-unit amount is a true per-unit rate — the only
9
+ * ones a Create Invoice line may be prefilled from. Typed against the entity
10
+ * union so a misspelt member fails to compile; a model added to the union
11
+ * still has to be classified here by hand (it is left out, so it fails closed:
12
+ * no prefill). The complement is `isTieredCatalogPricingModel`.
13
+ */
14
+ const PER_UNIT_RATE_PRICING_MODELS = [
15
+ 'per_unit',
16
+ 'flat_fee',
17
+ ];
18
+ /**
19
+ * Whether a price point's single-unit amount is a per-unit rate. A missing
20
+ * model means per-unit: the service defaults `pricing_model` to `per_unit`
21
+ * and older records may omit it.
22
+ */
23
+ const hasPerUnitRate = (pricingModel) => pricingModel == null ||
24
+ pricingModel === '' ||
25
+ PER_UNIT_RATE_PRICING_MODELS.some((model) => model === pricingModel);
26
+ /**
27
+ * The amount to prefill on a Create Invoice line for a price point, or
28
+ * `undefined` when there is no safe per-unit rate to prefill.
29
+ */
30
+ const planNamePrefillPrice = (pricePoint) => hasPerUnitRate(pricePoint.pricingModel)
31
+ ? invoicingPricePointDisplayAmount(pricePoint)?.amount
32
+ : undefined;
6
33
  /**
7
34
  * Display name for a customer option: company, else the full name, else the
8
35
  * email, else the raw id.
@@ -47,7 +74,7 @@ export const getCreateInvoiceFormView = (state) => {
47
74
  .filter((subFamily) => (subFamily.name ?? '') !== '')
48
75
  .map((subFamily) => ({
49
76
  planName: plan.name ?? '',
50
- price: subFamily.price?.amount,
77
+ price: planNamePrefillPrice(subFamily),
51
78
  subFamilyName: subFamily.name ?? '',
52
79
  }))),
53
80
  products: getInvoicingCatalogPrices(catalogListView.products),