@zeniai/client-epic-state 5.2.52-betaRD1 → 5.2.53

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 (88) hide show
  1. package/lib/entity/jeSchedules/jeSchedulesReducer.d.ts +1 -4
  2. package/lib/entity/jeSchedules/jeSchedulesReducer.js +5 -47
  3. package/lib/epic.d.ts +1 -2
  4. package/lib/epic.js +4 -6
  5. package/lib/esm/entity/jeSchedules/jeSchedulesReducer.js +4 -46
  6. package/lib/esm/epic.js +4 -6
  7. package/lib/esm/index.js +3 -3
  8. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +1 -9
  9. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +13 -10
  10. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +15 -34
  11. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +1 -12
  12. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
  13. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +1 -60
  14. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
  15. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +12 -20
  16. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -11
  17. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +45 -21
  18. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +4 -1
  19. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +19 -3
  20. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +16 -3
  21. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +6 -2
  22. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +4 -1
  23. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +21 -21
  24. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +6 -2
  25. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +10 -2
  26. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +33 -0
  27. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +43 -17
  28. package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +6 -2
  29. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +10 -2
  30. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +34 -0
  31. package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +44 -18
  32. package/lib/esm/view/invoicing/invoicingFormDraft.js +13 -0
  33. package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +57 -9
  34. package/lib/index.d.ts +3 -3
  35. package/lib/index.js +49 -50
  36. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.d.ts +2 -2
  37. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +0 -8
  38. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +11 -8
  39. package/lib/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +15 -34
  40. package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.d.ts +2 -2
  41. package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +1 -12
  42. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
  43. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +0 -18
  44. package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +18 -7
  45. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +2 -8
  46. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +3 -62
  47. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
  48. package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +0 -2
  49. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +8 -4
  50. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +12 -20
  51. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -10
  52. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +0 -15
  53. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +8 -5
  54. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +22 -6
  55. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +47 -22
  56. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +3 -0
  57. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +7 -0
  58. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +18 -2
  59. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +14 -1
  60. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +6 -2
  61. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +3 -0
  62. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +3 -2
  63. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +19 -19
  64. package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +6 -2
  65. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +3 -1
  66. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +10 -2
  67. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +7 -7
  68. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +33 -0
  69. package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +6 -0
  70. package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.d.ts +15 -10
  71. package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +42 -16
  72. package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +6 -2
  73. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.d.ts +3 -1
  74. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +10 -2
  75. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +7 -0
  76. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +34 -0
  77. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +6 -0
  78. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.d.ts +15 -11
  79. package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +42 -16
  80. package/lib/view/invoicing/invoicingFormDraft.d.ts +10 -1
  81. package/lib/view/invoicing/invoicingFormDraft.js +14 -0
  82. package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.d.ts +49 -0
  83. package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +59 -10
  84. package/package.json +1 -1
  85. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +0 -40
  86. package/lib/tsconfig.mocks.tsbuildinfo +0 -1
  87. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.d.ts +0 -20
  88. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +0 -44
@@ -84,9 +84,8 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
84
84
  one_time_accrual_service_month_end: parsedEndDate.format(jeSchedulesPayload_1.SERVICE_MONTH_FORMAT),
85
85
  // Existing lists what actually reached the books.
86
86
  one_time_accrual_statuses: ['posted'],
87
- // Kept only so this tab's response shape is unchanged. Nothing reads the failed
88
- // postings it returns any more -- they have their own endpoint and their own group
89
- // on Review. Dropping the key from the response is a server-side follow-up.
87
+ // A failed posting from an earlier month still needs to surface here, so this list
88
+ // is deliberately not windowed.
90
89
  filter_failed_je_postings_by_date: false,
91
90
  }),
92
91
  };
@@ -97,10 +96,12 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
97
96
  const updateActions = [];
98
97
  const accruedJeSchedules = response.data.accrued_je_schedules?.je_schedules ?? [];
99
98
  const oneTimeAccruals = response.data.one_time_accruals ?? [];
100
- // failed_je_postings is deliberately ignored. This endpoint windows it to the close
101
- // month, which is what hid older failures; fetchFailedJePostingsEpic owns that list
102
- // now and fetches it unwindowed.
103
- updateActions.push((0, jeSchedulesReducer_1.updateJESchedules)([...response.data.je_schedules]));
99
+ updateActions.push((0, jeSchedulesReducer_1.updateJESchedules)([
100
+ ...response.data.je_schedules,
101
+ ...response.data.failed_je_postings.je_schedules,
102
+ ]), (0, jeSchedulesReducer_1.updateJESchedulesDetails)([...response.data.failed_je_postings.je_schedules], response.data.failed_je_postings.scheduled_journal_entries), (0, jeSchedulesViewReducer_1.initializeJeScheduleLocalData)([
103
+ ...response.data.failed_je_postings.je_schedules,
104
+ ]));
104
105
  if (accruedJeSchedules.length > 0) {
105
106
  updateActions.push((0, jeSchedulesReducer_1.updateAccruedJESchedules)(accruedJeSchedules), (0, jeSchedulesReducer_1.updateAccruedJESchedulesDetails)(accruedJeSchedules, response.data.accrued_je_schedules
106
107
  ?.scheduled_journal_entries));
@@ -113,7 +114,9 @@ const fetchJeSchedulesEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, op
113
114
  }
114
115
  updateActions.push((0, jeSchedulesViewReducer_1.fetchJeSchedulesSuccess)({
115
116
  jeSchedules: [...response.data.je_schedules],
116
- failedJeSchedules: [],
117
+ failedJeSchedules: [
118
+ ...response.data.failed_je_postings.je_schedules,
119
+ ],
117
120
  accruedJeSchedules: accruedJeSchedules,
118
121
  oneTimeAccruals: oneTimeAccruals,
119
122
  selectedPeriod: selectedPeriod,
@@ -10,41 +10,22 @@ const initializeJeScheduleLocalDataEpic = (actions$, state$) => actions$.pipe((0
10
10
  const actions = [];
11
11
  const { jeScheduleTransactionKeys } = action.payload;
12
12
  jeScheduleTransactionKeys.forEach((jeScheduleTransactionKey) => {
13
- // Checked before the selector runs, not after: the selector destructures the record it
14
- // looks up, so a key that is not in the store throws a TypeError rather than returning
15
- // undefined. This epic is a mergeMap with no catchError, so that throw would take its
16
- // subscription down for the rest of the session and silently stop local-data
17
- // initialisation everywhere -- not just for this row.
18
- if (state.jeSchedulesState.schedulesByTransactionKey[jeScheduleTransactionKey] == null) {
19
- return;
20
- }
21
13
  const jeScheduledTransaction = (0, jeSchedulesSelector_1.getJEScheduledTransactionByJEScheduleTransactionKey)(jeScheduleTransactionKey, state);
22
- // One record per journal entry, not per schedule. A schedule that failed in two months is
23
- // two rows and each needs its own vendor / category edits -- keying only the first left
24
- // every later row without local data, which the list renders read-only and without a
25
- // Retry button. An empty array is possible when details have not landed yet; it must not
26
- // throw, because this runs in a mergeMap with no catchError and the throw would take the
27
- // epic's subscription down for the rest of the session.
28
- // Filtered on `error` for the same reason the selector is: this array is shared state, and
29
- // a schedule whose detail page has been opened holds every month it has, posted ones
30
- // included. The seeding and the rows must agree on which entries are failed postings.
31
- jeScheduledTransaction.scheduledJournalEntry
32
- .filter((journalEntry) => journalEntry.error.length > 0)
33
- .forEach((journalEntry) => {
34
- const { scheduledJournalEntryID } = journalEntry;
35
- actions.push((0, jeSchedulesViewReducer_1.updateJeScheduleLocalDataById)({
36
- localData: {
37
- jeScheduleType: jeScheduledTransaction.jeScheduleType,
38
- jeScheduleID: jeScheduledTransaction.jeScheduleId,
39
- scheduledJournalEntryID,
40
- updatedVendor: undefined,
41
- updatedCategoryId: undefined,
42
- updatedAccumulatedDepreciationCategoryID: undefined,
43
- updatedClassId: undefined,
44
- },
45
- scheduledJournalEntryID,
46
- }));
47
- });
14
+ const initLocalData = {
15
+ jeScheduleType: jeScheduledTransaction.jeScheduleType,
16
+ jeScheduleID: jeScheduledTransaction.jeScheduleId,
17
+ scheduledJournalEntryID: jeScheduledTransaction.scheduledJournalEntry[0]
18
+ .scheduledJournalEntryID,
19
+ updatedVendor: undefined,
20
+ updatedCategoryId: undefined,
21
+ updatedAccumulatedDepreciationCategoryID: undefined,
22
+ updatedClassId: undefined,
23
+ };
24
+ actions.push((0, jeSchedulesViewReducer_1.updateJeScheduleLocalDataById)({
25
+ localData: initLocalData,
26
+ scheduledJournalEntryID: jeScheduledTransaction.scheduledJournalEntry[0]
27
+ .scheduledJournalEntryID,
28
+ }));
48
29
  });
49
30
  return (0, rxjs_1.from)(actions);
50
31
  }));
@@ -1,10 +1,10 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { Observable } from 'rxjs';
3
- import { removeScheduledJournalEntryFromJESchedule, updateJESchedules, updateJESchedulesDetails } from '../../../../entity/jeSchedules/jeSchedulesReducer';
3
+ import { updateJESchedules, updateJESchedulesDetails } from '../../../../entity/jeSchedules/jeSchedulesReducer';
4
4
  import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
5
5
  import { RootState } from '../../../../rootStateTypes';
6
6
  import { ZeniAPI } from '../../../../zeniAPI';
7
7
  import { fetchMonthEndCloseChecks } from '../../../monthEndCloseChecksView/monthEndCloseChecksViewReducer';
8
8
  import { removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, updateJeScheduleTransactionKeys } from '../../reducers/jeSchedulesViewReducer';
9
- export type ActionType = ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeFailedJeScheduleTransactionKey> | ReturnType<typeof removeJeScheduleLocalDataById> | ReturnType<typeof removeScheduledJournalEntryFromJESchedule> | ReturnType<typeof retryJeSchedule> | ReturnType<typeof retryJeScheduleFailure> | ReturnType<typeof retryJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof updateJeScheduleTransactionKeys>;
9
+ export type ActionType = ReturnType<typeof fetchMonthEndCloseChecks> | ReturnType<typeof openSnackbar> | ReturnType<typeof removeFailedJeScheduleTransactionKey> | ReturnType<typeof removeJeScheduleLocalDataById> | ReturnType<typeof retryJeSchedule> | ReturnType<typeof retryJeScheduleFailure> | ReturnType<typeof retryJeScheduleSuccess> | ReturnType<typeof updateJESchedules> | ReturnType<typeof updateJESchedulesDetails> | ReturnType<typeof updateJeScheduleTransactionKeys>;
10
10
  export declare const retryJeScheduleEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.retryJeScheduleEpic = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
- const jeSchedulesReducer_1 = require("../../../../entity/jeSchedules/jeSchedulesReducer");
7
6
  const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
8
7
  const tenantSelector_1 = require("../../../../entity/tenant/tenantSelector");
9
8
  const responsePayload_1 = require("../../../../responsePayload");
@@ -26,16 +25,9 @@ const retryJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
26
25
  .pipe((0, operators_1.mergeMap)((response) => {
27
26
  if ((0, responsePayload_1.isSuccessStatus)(response)) {
28
27
  const updateActions = [];
29
- // Retire this entry, and the schedule itself only when this was its last failed
30
- // one. A schedule that failed in several months is several rows sharing one
31
- // schedule key, so dropping the key outright took the still-failing months off the
32
- // list with it and nothing would have surfaced them again.
33
- const failedEntriesForSchedule = state.jeSchedulesState.schedulesByTransactionKey[jeScheduleTransactionKey]?.scheduledJournalEntry ?? [];
34
- const wasLastFailedEntryForSchedule = failedEntriesForSchedule.filter((journalEntry) => journalEntry.scheduledJournalEntryID !==
35
- scheduledJournalEntryID).length === 0;
36
28
  updateActions.push((0, jeSchedulesViewReducer_1.retryJeScheduleSuccess)({
37
29
  scheduledJournalEntryID,
38
- }), (0, jeSchedulesReducer_1.removeScheduledJournalEntryFromJESchedule)(jeScheduleTransactionKey, scheduledJournalEntryID), (0, jeSchedulesViewReducer_1.removeJeScheduleLocalDataById)({ scheduledJournalEntryID }), // Important to remove localdata after success.
30
+ }), (0, jeSchedulesViewReducer_1.removeFailedJeScheduleTransactionKey)(jeScheduleTransactionKey, selectedPeriod), (0, jeSchedulesViewReducer_1.removeJeScheduleLocalDataById)({ scheduledJournalEntryID }), // Important to remove localdata after success.
39
31
  (0, monthEndCloseChecksViewReducer_1.fetchMonthEndCloseChecks)({
40
32
  tenantId: currentTenant.tenantId,
41
33
  period: selectedPeriod,
@@ -45,9 +37,6 @@ const retryJeScheduleEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, ope
45
37
  messageText: 'success',
46
38
  type: 'success',
47
39
  }));
48
- if (wasLastFailedEntryForSchedule) {
49
- updateActions.push((0, jeSchedulesViewReducer_1.removeFailedJeScheduleTransactionKey)(jeScheduleTransactionKey, selectedPeriod));
50
- }
51
40
  return (0, rxjs_1.from)(updateActions);
52
41
  }
53
42
  else {
@@ -9,7 +9,6 @@ const transactionReducer_1 = require("../../../../entity/transaction/transaction
9
9
  const responsePayload_1 = require("../../../../responsePayload");
10
10
  const transactionCategorizationLocalDataHelper_1 = require("../../helpers/transactionCategorizationLocalDataHelper");
11
11
  const transactionsViewReducer_1 = require("../../reducers/transactionsViewReducer");
12
- const completedSubTab_1 = require("../../types/completedSubTab");
13
12
  const transactionsViewState_1 = require("../../types/transactionsViewState");
14
13
  const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionsViewReducer_1.fetchTransactionCategorization.match),
15
14
  // Per-tab switchMap: cancels in-flight requests for the same tab on a new
@@ -36,9 +35,10 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
36
35
  // cross-status search (omit or true) is reserved for Receipts
37
36
  // manual-match.
38
37
  search_all_statuses: false,
39
- sub_tab: selectedTab === 'autoCategorized'
40
- ? expenseAutomationTransactionsViewState.selectedTransactionCategorizationCompletedSubTab
41
- : completedSubTab_1.DEFAULT_COMPLETED_SUB_TAB,
38
+ // Sent on both tabs: the backend ignores it for Review's own rows but uses
39
+ // it to scope the Completed badge it returns alongside them.
40
+ sub_tab: expenseAutomationTransactionsViewState
41
+ .selectedTransactionCategorizationCompletedSubTab,
42
42
  transaction_group: expenseAutomationTransactionsViewState.selectedTransactionGroup,
43
43
  };
44
44
  return zeniAPI
@@ -90,6 +90,17 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
90
90
  parentTotalCount: response.data.parent_tab_total_count ??
91
91
  response.data.total_count,
92
92
  }));
93
+ // The inactive tab's badge, counted under the same filters. Absent on
94
+ // pages after the first and on the cross-tab search path, where the
95
+ // last known value stays correct.
96
+ const otherTabTotalCount = response.data.other_tab_total_count;
97
+ if (otherTabTotalCount != null) {
98
+ updateActions.push((0, transactionsViewReducer_1.updateParentTotalCountForTab)({
99
+ selectedPeriod,
100
+ selectedTab: selectedTab === 'review' ? 'autoCategorized' : 'review',
101
+ parentTotalCount: otherTabTotalCount,
102
+ }));
103
+ }
93
104
  updateActions.push((0, transactionsViewReducer_1.resetOtherTabsFetchState)({
94
105
  refreshViewInBackground,
95
106
  tabs: transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => selectedTab !== tab),
@@ -78,24 +78,6 @@ interface ExpenseAutomationJESchedulesPayload {
78
78
  };
79
79
  }
80
80
  export type ExpenseAutomationJESchedulesResponse = ZeniAPIResponse<ExpenseAutomationJESchedulesPayload>;
81
- /**
82
- * `GET /1.0/expenses_automation/failed_je_postings`.
83
- *
84
- * Deliberately the same `failed_je_postings` shape the schedules endpoint sends under that key, so
85
- * both responses feed the same mappers. The difference is what the server does before answering:
86
- * this endpoint applies no date window, so a posting that failed months ago still comes back.
87
- */
88
- export interface FailedJePostingsPayload {
89
- je_schedules: JEScheduledTransactionPayload[];
90
- scheduled_journal_entries: ScheduledJournalEntryPayload[];
91
- }
92
- interface ExpenseAutomationFailedJePostingsPayload {
93
- failed_je_postings: FailedJePostingsPayload;
94
- query?: {
95
- expected_post_start_date: string | null;
96
- };
97
- }
98
- export type ExpenseAutomationFailedJePostingsResponse = ZeniAPIResponse<ExpenseAutomationFailedJePostingsPayload>;
99
81
  export declare const SERVICE_MONTH_FORMAT = "YYYY-MM";
100
82
  export interface CreateOneTimeAccrualPayload {
101
83
  amount: number;
@@ -15,9 +15,9 @@ export interface TransactionCategorizationQueryPayload {
15
15
  start_date: string | null;
16
16
  /**
17
17
  * Required. For the Completed (`auto_categorized=true`) listing, scopes the
18
- * returned page + `total_count` to one of the Completed sub-tabs. For the
19
- * Review listing it is forced to `'all'` to preserve parent-tab semantics
20
- * on the backend.
18
+ * returned page + `total_count` to one of the Completed sub-tabs. It is sent
19
+ * on the Review listing too: the backend ignores it for Review's own status
20
+ * set, but uses it to scope the Completed badge in `other_tab_total_count`.
21
21
  */
22
22
  sub_tab: CompletedSubTab;
23
23
  /**
@@ -44,10 +44,21 @@ export interface TransactionCategorizationPayload {
44
44
  total_count: number;
45
45
  transactions: SupportedTransactionPayload[];
46
46
  /**
47
- * Count of transactions for the entire parent tab (Review or Completed),
48
- * regardless of which sub-tab the listing was scoped to. Used solely to
49
- * drive the parent tab badge counts on the UI; pagination, list-level
50
- * counts, and sub-tab chips continue to consume {@link total_count}.
47
+ * Badge count for the OTHER tab (Completed when this response is Review, and
48
+ * vice versa) under the same filters, so both badges move together with the
49
+ * Transaction Group dropdown and the Completed sub-tab without having to
50
+ * fetch that tab's rows.
51
+ *
52
+ * `null`/absent when the backend computed no badge — pages after the first
53
+ * (a scroll cannot change either badge) and the cross-tab search path used by
54
+ * Receipts manual-match. Consumers must keep their last known value then.
55
+ */
56
+ other_tab_total_count?: number | null;
57
+ /**
58
+ * Badge count for the tab this response belongs to, taken under every filter
59
+ * the request carried (`transaction_group`, `sub_tab`, `search_text`) — so it
60
+ * matches the rows rendered below it and equals {@link total_count}. Retained
61
+ * as its own key for wire compatibility.
51
62
  *
52
63
  * Optional at the wire boundary so that any version-skew scenario
53
64
  * (delayed BE rollout, cached SW response, hotfix without the BE change)
@@ -47,13 +47,7 @@ export declare const clearExpenseAutomationJESchedulesView: import("@reduxjs/too
47
47
  period: TimePeriod;
48
48
  refreshViewInBackground: any;
49
49
  selectedPageTab: "schedules" | "actual_matching" | "existing_schedules" | undefined;
50
- }, "expenseAutomationJESchedulesView/fetchJeSchedules", never, never>, fetchFailedJePostings: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[refreshInBackground?: any], {
51
- refreshInBackground: any;
52
- }, "expenseAutomationJESchedulesView/fetchFailedJePostings", never, never>, fetchFailedJePostingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[status: ZeniAPIStatus<Record<string, unknown>>], {
53
- status: ZeniAPIStatus<Record<string, unknown>>;
54
- }, "expenseAutomationJESchedulesView/fetchFailedJePostingsFailure", never, never>, fetchFailedJePostingsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[failedJeSchedules: JEScheduledTransactionPayload[]], {
55
- failedJeSchedules: JEScheduledTransactionPayload[];
56
- }, "expenseAutomationJESchedulesView/fetchFailedJePostingsSuccess", never, never>, fetchJeSchedulesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
50
+ }, "expenseAutomationJESchedulesView/fetchJeSchedules", never, never>, fetchJeSchedulesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
57
51
  selectedPageTab: JEPageTab;
58
52
  selectedPeriod: MonthYearPeriod;
59
53
  status: ZeniAPIStatus;
@@ -138,7 +132,7 @@ export declare const clearExpenseAutomationJESchedulesView: import("@reduxjs/too
138
132
  status: ZeniAPIStatus;
139
133
  }, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleFailure">, searchTransactionsForNewScheduleSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
140
134
  searchResults: JEScheduleTransactionKey[];
141
- }, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleSuccess">, toggleJECreatedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJECreatedGroupCollapsed">, toggleJEFailedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEFailedGroupCollapsed">, toggleJEPendingGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEPendingGroupCollapsed">, updateAccountSettingsListForAccountTypes: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
135
+ }, "expenseAutomationJESchedulesView/searchTransactionsForNewScheduleSuccess">, toggleJECreatedGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJECreatedGroupCollapsed">, toggleJEPendingGroupCollapsed: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"expenseAutomationJESchedulesView/toggleJEPendingGroupCollapsed">, updateAccountSettingsListForAccountTypes: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
142
136
  accountPayload: AccountMetadataPayload[];
143
137
  }, "expenseAutomationJESchedulesView/updateAccountSettingsListForAccountTypes">, updateAccountSettingsListForAccountTypesFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
144
138
  status: ZeniAPIStatus;
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.saveAccountSettingsLocalData = exports.saveAccountSettingsFailure = exports.saveAccountSettings = exports.retryJeScheduleSuccess = exports.retryJeScheduleFailure = exports.retryJeSchedule = exports.resetNewScheduleLocalData = exports.removeJeScheduleTransactionKey = exports.removeJeAccruedScheduleKey = exports.removeJeScheduleLocalDataById = exports.removeJeOneTimeAccrualLocalData = exports.removeFailedJeScheduleTransactionKey = exports.initializeNewSchedule = exports.initializeJeScheduleLocalData = exports.initializeAccountSettingsView = exports.ignoreRecommendedJeScheduleSuccess = exports.ignoreRecommendedJeScheduleFailure = exports.ignoreRecommendedJeSchedule = exports.fetchRecommendationForAccountSettings = exports.fetchOneTimeAccrualSuccess = exports.fetchOneTimeAccrualFailure = exports.fetchOneTimeAccrual = exports.fetchJeSchedulesSuccess = exports.fetchJeSchedulesPage = exports.fetchJeSchedulesFailure = exports.fetchFailedJePostingsSuccess = exports.fetchFailedJePostingsFailure = exports.fetchFailedJePostings = exports.fetchJeSchedules = exports.fetchAccountSettingsListForAccountTypes = exports.revertOneTimeAccrual = exports.revertJeScheduleSuccess = exports.revertJeScheduleFailure = exports.revertJeSchedule = exports.promoteOneTimeAccrual = exports.oneTimeAccrualActionSuccess = exports.oneTimeAccrualActionFailure = exports.ignoreOneTimeAccrual = exports.createOneTimeAccrualSuccess = exports.createOneTimeAccrualFailure = exports.createOneTimeAccrual = exports.clearSearchTransactionsForNewSchedule = exports.clearJeScheduleLocalData = exports.clearJeAccountSettingsLocalData = exports.clearExpenseAutomationJESchedulesView = exports.initialState = exports.searchTransactionsInitialState = exports.newScheduleInitialState = exports.getBaseNewScheduleLocalData = exports.accountSettingsInitialState = void 0;
5
- exports.updateRecommendationForAccountSettingsFailure = exports.updateRecommendationForAccountSettings = exports.updateNewScheduleLocalData = exports.updateJeScheduleTransactionKeys = exports.updateJeScheduleLocalDataById = exports.updateJeOneTimeAccrualLocalData = exports.updateJEScheduleTypeFilter = exports.updateJESchedulesUIState = exports.updateAccountSettingsListForAccountTypesFailure = exports.updateAccountSettingsListForAccountTypes = exports.toggleJEPendingGroupCollapsed = exports.toggleJEFailedGroupCollapsed = exports.toggleJECreatedGroupCollapsed = exports.searchTransactionsForNewScheduleSuccess = exports.searchTransactionsForNewScheduleFailure = exports.searchTransactionsForNewSchedule = exports.saveNewScheduleSuccess = exports.saveNewScheduleFailure = exports.saveNewSchedule = exports.saveAccountSettingsSuccess = void 0;
4
+ exports.saveNewScheduleFailure = exports.saveNewSchedule = exports.saveAccountSettingsSuccess = exports.saveAccountSettingsLocalData = exports.saveAccountSettingsFailure = exports.saveAccountSettings = exports.retryJeScheduleSuccess = exports.retryJeScheduleFailure = exports.retryJeSchedule = exports.resetNewScheduleLocalData = exports.removeJeScheduleTransactionKey = exports.removeJeAccruedScheduleKey = exports.removeJeScheduleLocalDataById = exports.removeJeOneTimeAccrualLocalData = exports.removeFailedJeScheduleTransactionKey = exports.initializeNewSchedule = exports.initializeJeScheduleLocalData = exports.initializeAccountSettingsView = exports.ignoreRecommendedJeScheduleSuccess = exports.ignoreRecommendedJeScheduleFailure = exports.ignoreRecommendedJeSchedule = exports.fetchRecommendationForAccountSettings = exports.fetchOneTimeAccrualSuccess = exports.fetchOneTimeAccrualFailure = exports.fetchOneTimeAccrual = exports.fetchJeSchedulesSuccess = exports.fetchJeSchedulesPage = exports.fetchJeSchedulesFailure = exports.fetchJeSchedules = exports.fetchAccountSettingsListForAccountTypes = exports.revertOneTimeAccrual = exports.revertJeScheduleSuccess = exports.revertJeScheduleFailure = exports.revertJeSchedule = exports.promoteOneTimeAccrual = exports.oneTimeAccrualActionSuccess = exports.oneTimeAccrualActionFailure = exports.ignoreOneTimeAccrual = exports.createOneTimeAccrualSuccess = exports.createOneTimeAccrualFailure = exports.createOneTimeAccrual = exports.clearSearchTransactionsForNewSchedule = exports.clearJeScheduleLocalData = exports.clearJeAccountSettingsLocalData = exports.clearExpenseAutomationJESchedulesView = exports.initialState = exports.searchTransactionsInitialState = exports.newScheduleInitialState = exports.getBaseNewScheduleLocalData = exports.accountSettingsInitialState = void 0;
5
+ exports.updateRecommendationForAccountSettingsFailure = exports.updateRecommendationForAccountSettings = exports.updateNewScheduleLocalData = exports.updateJeScheduleTransactionKeys = exports.updateJeScheduleLocalDataById = exports.updateJeOneTimeAccrualLocalData = exports.updateJEScheduleTypeFilter = exports.updateJESchedulesUIState = exports.updateAccountSettingsListForAccountTypesFailure = exports.updateAccountSettingsListForAccountTypes = exports.toggleJEPendingGroupCollapsed = exports.toggleJECreatedGroupCollapsed = exports.searchTransactionsForNewScheduleSuccess = exports.searchTransactionsForNewScheduleFailure = exports.searchTransactionsForNewSchedule = exports.saveNewScheduleSuccess = void 0;
6
6
  const toolkit_1 = require("@reduxjs/toolkit");
7
7
  const getNestedAccountIDHierarchyForReport_1 = require("../../../commonStateTypes/accountView/getNestedAccountIDHierarchyForReport");
8
8
  const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
@@ -68,10 +68,6 @@ exports.initialState = {
68
68
  jeScheduleAccruedKeysByPeriodAndTab: {},
69
69
  jeScheduleOneTimeAccrualKeysByPeriodAndTab: {},
70
70
  failedJeScheduleTransactionKeysByPeriodAndTab: {},
71
- failedJePostings: {
72
- fetchState: { fetchState: 'Not-Started', error: undefined },
73
- jeScheduleTransactionKeys: [],
74
- },
75
71
  postStatusById: {},
76
72
  ignoreStatusById: {},
77
73
  revertStatusById: {},
@@ -81,9 +77,6 @@ exports.initialState = {
81
77
  oneTimeAccrualFetchStatusById: {},
82
78
  uiState: {
83
79
  createdGroupCollapsed: false,
84
- // Expanded, like the other two. A failed posting is the only thing on this page that is
85
- // actively wrong, so folding it away by default would hide the reason to open the tab.
86
- failedGroupCollapsed: false,
87
80
  pendingGroupCollapsed: false,
88
81
  scrollPosition: { scrollTop: 0, scrollLeft: undefined },
89
82
  searchString: '',
@@ -155,53 +148,6 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
155
148
  };
156
149
  },
157
150
  },
158
- /**
159
- * The Failed Postings list, fetched separately from the schedules it belongs to.
160
- *
161
- * No period and no tab in any of these three: the endpoint applies no date window, so there is
162
- * one list per tenant and one slot to hold it. `refreshInBackground` keeps a silent refetch
163
- * from dropping a skeleton over rows already on screen, the same way refreshStatus does for
164
- * the schedules list.
165
- */
166
- fetchFailedJePostings: {
167
- reducer(draft, action) {
168
- if (!action.payload.refreshInBackground) {
169
- draft.failedJePostings.fetchState = {
170
- fetchState: 'In-Progress',
171
- error: undefined,
172
- };
173
- }
174
- },
175
- prepare(refreshInBackground = false) {
176
- return { payload: { refreshInBackground } };
177
- },
178
- },
179
- fetchFailedJePostingsSuccess: {
180
- reducer(draft, action) {
181
- draft.failedJePostings = {
182
- fetchState: { fetchState: 'Completed', error: undefined },
183
- jeScheduleTransactionKeys: action.payload.failedJeSchedules.map((schedule) => (0, jeSchedulesPayload_1.getJEScheduleTransactionDetailKeyPayload)(schedule.base_transaction)),
184
- };
185
- },
186
- prepare(failedJeSchedules) {
187
- return { payload: { failedJeSchedules } };
188
- },
189
- },
190
- fetchFailedJePostingsFailure: {
191
- reducer(draft, action) {
192
- // Keys are deliberately left alone. The schedules list clears its buckets on failure so an
193
- // errored tab cannot read as "these are all the schedules there are", but this list is a
194
- // set of outstanding problems -- showing the last known ones beside an error beats
195
- // implying there are none.
196
- draft.failedJePostings.fetchState = {
197
- fetchState: 'Error',
198
- error: action.payload.status,
199
- };
200
- },
201
- prepare(status) {
202
- return { payload: { status } };
203
- },
204
- },
205
151
  fetchJeSchedulesSuccess(draft, action) {
206
152
  const { jeSchedules, selectedPeriod, selectedPageTab, failedJeSchedules, accruedJeSchedules, oneTimeAccruals, refreshViewInBackground, } = action.payload;
207
153
  const periodTabKey = (0, jeSchedulesViewState_1.getJESchedulePeriodTabKey)(selectedPageTab, (0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod));
@@ -418,8 +364,6 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
418
364
  reducer(draft, action) {
419
365
  const { failedJeScheduleKey } = action.payload;
420
366
  removeKeyFromEveryTabSlot(draft.failedJeScheduleTransactionKeysByPeriodAndTab, failedJeScheduleKey);
421
- draft.failedJePostings.jeScheduleTransactionKeys =
422
- draft.failedJePostings.jeScheduleTransactionKeys.filter((jeScheduleKey) => jeScheduleKey !== failedJeScheduleKey);
423
367
  },
424
368
  },
425
369
  initializeJeScheduleLocalData: {
@@ -762,9 +706,6 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
762
706
  draft.uiState.createdGroupCollapsed =
763
707
  !draft.uiState.createdGroupCollapsed;
764
708
  },
765
- toggleJEFailedGroupCollapsed(draft) {
766
- draft.uiState.failedGroupCollapsed = !draft.uiState.failedGroupCollapsed;
767
- },
768
709
  clearExpenseAutomationJESchedulesView(draft) {
769
710
  Object.assign(draft, exports.initialState);
770
711
  },
@@ -775,7 +716,7 @@ const expenseAutomationJESchedulesView = (0, toolkit_1.createSlice)({
775
716
  });
776
717
  },
777
718
  });
778
- _a = expenseAutomationJESchedulesView.actions, exports.clearExpenseAutomationJESchedulesView = _a.clearExpenseAutomationJESchedulesView, exports.clearJeAccountSettingsLocalData = _a.clearJeAccountSettingsLocalData, exports.clearJeScheduleLocalData = _a.clearJeScheduleLocalData, exports.clearSearchTransactionsForNewSchedule = _a.clearSearchTransactionsForNewSchedule, exports.createOneTimeAccrual = _a.createOneTimeAccrual, exports.createOneTimeAccrualFailure = _a.createOneTimeAccrualFailure, exports.createOneTimeAccrualSuccess = _a.createOneTimeAccrualSuccess, exports.ignoreOneTimeAccrual = _a.ignoreOneTimeAccrual, exports.oneTimeAccrualActionFailure = _a.oneTimeAccrualActionFailure, exports.oneTimeAccrualActionSuccess = _a.oneTimeAccrualActionSuccess, exports.promoteOneTimeAccrual = _a.promoteOneTimeAccrual, exports.revertJeSchedule = _a.revertJeSchedule, exports.revertJeScheduleFailure = _a.revertJeScheduleFailure, exports.revertJeScheduleSuccess = _a.revertJeScheduleSuccess, exports.revertOneTimeAccrual = _a.revertOneTimeAccrual, exports.fetchAccountSettingsListForAccountTypes = _a.fetchAccountSettingsListForAccountTypes, exports.fetchJeSchedules = _a.fetchJeSchedules, exports.fetchFailedJePostings = _a.fetchFailedJePostings, exports.fetchFailedJePostingsFailure = _a.fetchFailedJePostingsFailure, exports.fetchFailedJePostingsSuccess = _a.fetchFailedJePostingsSuccess, exports.fetchJeSchedulesFailure = _a.fetchJeSchedulesFailure, exports.fetchJeSchedulesPage = _a.fetchJeSchedulesPage, exports.fetchJeSchedulesSuccess = _a.fetchJeSchedulesSuccess, exports.fetchOneTimeAccrual = _a.fetchOneTimeAccrual, exports.fetchOneTimeAccrualFailure = _a.fetchOneTimeAccrualFailure, exports.fetchOneTimeAccrualSuccess = _a.fetchOneTimeAccrualSuccess, exports.fetchRecommendationForAccountSettings = _a.fetchRecommendationForAccountSettings, exports.ignoreRecommendedJeSchedule = _a.ignoreRecommendedJeSchedule, exports.ignoreRecommendedJeScheduleFailure = _a.ignoreRecommendedJeScheduleFailure, exports.ignoreRecommendedJeScheduleSuccess = _a.ignoreRecommendedJeScheduleSuccess, exports.initializeAccountSettingsView = _a.initializeAccountSettingsView, exports.initializeJeScheduleLocalData = _a.initializeJeScheduleLocalData, exports.initializeNewSchedule = _a.initializeNewSchedule, exports.removeFailedJeScheduleTransactionKey = _a.removeFailedJeScheduleTransactionKey, exports.removeJeOneTimeAccrualLocalData = _a.removeJeOneTimeAccrualLocalData, exports.removeJeScheduleLocalDataById = _a.removeJeScheduleLocalDataById, exports.removeJeAccruedScheduleKey = _a.removeJeAccruedScheduleKey, exports.removeJeScheduleTransactionKey = _a.removeJeScheduleTransactionKey, exports.resetNewScheduleLocalData = _a.resetNewScheduleLocalData, exports.retryJeSchedule = _a.retryJeSchedule, exports.retryJeScheduleFailure = _a.retryJeScheduleFailure, exports.retryJeScheduleSuccess = _a.retryJeScheduleSuccess, exports.saveAccountSettings = _a.saveAccountSettings, exports.saveAccountSettingsFailure = _a.saveAccountSettingsFailure, exports.saveAccountSettingsLocalData = _a.saveAccountSettingsLocalData, exports.saveAccountSettingsSuccess = _a.saveAccountSettingsSuccess, exports.saveNewSchedule = _a.saveNewSchedule, exports.saveNewScheduleFailure = _a.saveNewScheduleFailure, exports.saveNewScheduleSuccess = _a.saveNewScheduleSuccess, exports.searchTransactionsForNewSchedule = _a.searchTransactionsForNewSchedule, exports.searchTransactionsForNewScheduleFailure = _a.searchTransactionsForNewScheduleFailure, exports.searchTransactionsForNewScheduleSuccess = _a.searchTransactionsForNewScheduleSuccess, exports.toggleJECreatedGroupCollapsed = _a.toggleJECreatedGroupCollapsed, exports.toggleJEFailedGroupCollapsed = _a.toggleJEFailedGroupCollapsed, exports.toggleJEPendingGroupCollapsed = _a.toggleJEPendingGroupCollapsed, exports.updateAccountSettingsListForAccountTypes = _a.updateAccountSettingsListForAccountTypes, exports.updateAccountSettingsListForAccountTypesFailure = _a.updateAccountSettingsListForAccountTypesFailure, exports.updateJESchedulesUIState = _a.updateJESchedulesUIState, exports.updateJEScheduleTypeFilter = _a.updateJEScheduleTypeFilter, exports.updateJeOneTimeAccrualLocalData = _a.updateJeOneTimeAccrualLocalData, exports.updateJeScheduleLocalDataById = _a.updateJeScheduleLocalDataById, exports.updateJeScheduleTransactionKeys = _a.updateJeScheduleTransactionKeys, exports.updateNewScheduleLocalData = _a.updateNewScheduleLocalData, exports.updateRecommendationForAccountSettings = _a.updateRecommendationForAccountSettings, exports.updateRecommendationForAccountSettingsFailure = _a.updateRecommendationForAccountSettingsFailure;
719
+ _a = expenseAutomationJESchedulesView.actions, exports.clearExpenseAutomationJESchedulesView = _a.clearExpenseAutomationJESchedulesView, exports.clearJeAccountSettingsLocalData = _a.clearJeAccountSettingsLocalData, exports.clearJeScheduleLocalData = _a.clearJeScheduleLocalData, exports.clearSearchTransactionsForNewSchedule = _a.clearSearchTransactionsForNewSchedule, exports.createOneTimeAccrual = _a.createOneTimeAccrual, exports.createOneTimeAccrualFailure = _a.createOneTimeAccrualFailure, exports.createOneTimeAccrualSuccess = _a.createOneTimeAccrualSuccess, exports.ignoreOneTimeAccrual = _a.ignoreOneTimeAccrual, exports.oneTimeAccrualActionFailure = _a.oneTimeAccrualActionFailure, exports.oneTimeAccrualActionSuccess = _a.oneTimeAccrualActionSuccess, exports.promoteOneTimeAccrual = _a.promoteOneTimeAccrual, exports.revertJeSchedule = _a.revertJeSchedule, exports.revertJeScheduleFailure = _a.revertJeScheduleFailure, exports.revertJeScheduleSuccess = _a.revertJeScheduleSuccess, exports.revertOneTimeAccrual = _a.revertOneTimeAccrual, exports.fetchAccountSettingsListForAccountTypes = _a.fetchAccountSettingsListForAccountTypes, exports.fetchJeSchedules = _a.fetchJeSchedules, exports.fetchJeSchedulesFailure = _a.fetchJeSchedulesFailure, exports.fetchJeSchedulesPage = _a.fetchJeSchedulesPage, exports.fetchJeSchedulesSuccess = _a.fetchJeSchedulesSuccess, exports.fetchOneTimeAccrual = _a.fetchOneTimeAccrual, exports.fetchOneTimeAccrualFailure = _a.fetchOneTimeAccrualFailure, exports.fetchOneTimeAccrualSuccess = _a.fetchOneTimeAccrualSuccess, exports.fetchRecommendationForAccountSettings = _a.fetchRecommendationForAccountSettings, exports.ignoreRecommendedJeSchedule = _a.ignoreRecommendedJeSchedule, exports.ignoreRecommendedJeScheduleFailure = _a.ignoreRecommendedJeScheduleFailure, exports.ignoreRecommendedJeScheduleSuccess = _a.ignoreRecommendedJeScheduleSuccess, exports.initializeAccountSettingsView = _a.initializeAccountSettingsView, exports.initializeJeScheduleLocalData = _a.initializeJeScheduleLocalData, exports.initializeNewSchedule = _a.initializeNewSchedule, exports.removeFailedJeScheduleTransactionKey = _a.removeFailedJeScheduleTransactionKey, exports.removeJeOneTimeAccrualLocalData = _a.removeJeOneTimeAccrualLocalData, exports.removeJeScheduleLocalDataById = _a.removeJeScheduleLocalDataById, exports.removeJeAccruedScheduleKey = _a.removeJeAccruedScheduleKey, exports.removeJeScheduleTransactionKey = _a.removeJeScheduleTransactionKey, exports.resetNewScheduleLocalData = _a.resetNewScheduleLocalData, exports.retryJeSchedule = _a.retryJeSchedule, exports.retryJeScheduleFailure = _a.retryJeScheduleFailure, exports.retryJeScheduleSuccess = _a.retryJeScheduleSuccess, exports.saveAccountSettings = _a.saveAccountSettings, exports.saveAccountSettingsFailure = _a.saveAccountSettingsFailure, exports.saveAccountSettingsLocalData = _a.saveAccountSettingsLocalData, exports.saveAccountSettingsSuccess = _a.saveAccountSettingsSuccess, exports.saveNewSchedule = _a.saveNewSchedule, exports.saveNewScheduleFailure = _a.saveNewScheduleFailure, exports.saveNewScheduleSuccess = _a.saveNewScheduleSuccess, exports.searchTransactionsForNewSchedule = _a.searchTransactionsForNewSchedule, exports.searchTransactionsForNewScheduleFailure = _a.searchTransactionsForNewScheduleFailure, exports.searchTransactionsForNewScheduleSuccess = _a.searchTransactionsForNewScheduleSuccess, exports.toggleJECreatedGroupCollapsed = _a.toggleJECreatedGroupCollapsed, exports.toggleJEPendingGroupCollapsed = _a.toggleJEPendingGroupCollapsed, exports.updateAccountSettingsListForAccountTypes = _a.updateAccountSettingsListForAccountTypes, exports.updateAccountSettingsListForAccountTypesFailure = _a.updateAccountSettingsListForAccountTypesFailure, exports.updateJESchedulesUIState = _a.updateJESchedulesUIState, exports.updateJEScheduleTypeFilter = _a.updateJEScheduleTypeFilter, exports.updateJeOneTimeAccrualLocalData = _a.updateJeOneTimeAccrualLocalData, exports.updateJeScheduleLocalDataById = _a.updateJeScheduleLocalDataById, exports.updateJeScheduleTransactionKeys = _a.updateJeScheduleTransactionKeys, exports.updateNewScheduleLocalData = _a.updateNewScheduleLocalData, exports.updateRecommendationForAccountSettings = _a.updateRecommendationForAccountSettings, exports.updateRecommendationForAccountSettingsFailure = _a.updateRecommendationForAccountSettingsFailure;
779
720
  exports.default = expenseAutomationJESchedulesView.reducer;
780
721
  const doUpdateRecommendationForAccountSettings = (draft, payload) => {
781
722
  const { prepaidExpensesRecommendations, fixedAssetsRecommendations, accruedExpensesRecommendations, } = (0, accountTypeRecommendationPayload_1.mapAccountTypeRecommendationPayloadToAccountRecommendationByType)(payload);
@@ -380,6 +380,16 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
380
380
  if (cached != null) {
381
381
  autoCat.uiState.pageToken = cached.pageToken;
382
382
  autoCat.uiState.totalCount = { ...cached.totalCount };
383
+ // Keep the stored badge in step with the restored sub-tab: the selector
384
+ // falls back to it for any period this sub-tab has not loaded. Merged,
385
+ // not replaced -- the snapshot only holds periods this sub-tab actually
386
+ // loaded, while the badge map also carries periods filled from a Review
387
+ // response's `other_tab_total_count`. Overwriting would drop those and
388
+ // leave the badge at 0 for any period this sub-tab never visited.
389
+ draft.parentTotalCountByTab.autoCategorized = {
390
+ ...draft.parentTotalCountByTab.autoCategorized,
391
+ ...cached.totalCount,
392
+ };
383
393
  autoCat.uiState.scrollPosition = cached.scrollPosition;
384
394
  autoCat.transactionIdsBySelectedPeriod = {
385
395
  ...cached.transactionIdsBySelectedPeriod,
@@ -47,7 +47,6 @@ export interface ExpenseAutomationJESchedulesViewSelector extends SelectorView {
47
47
  completionStatus: CompletionStatusType;
48
48
  createdSchedules: JEScheduleRow[];
49
49
  createdTotal: number;
50
- failedPostings: JEScheduledTransactionWithFailedEntries[];
51
50
  hasLoadedForSelectedTab: boolean;
52
51
  ignoreStatusById: Record<JEScheduleTransactionKey, FetchStateAndError>;
53
52
  jeScheduleLocalDataById: Record<ID, JEScheduleLocalData>;
@@ -62,7 +61,6 @@ export interface ExpenseAutomationJESchedulesViewSelector extends SelectorView {
62
61
  pendingReviewTotal: number;
63
62
  postStatusById: Record<ID, FetchStateAndError>;
64
63
  refreshStatus: FetchStateAndError;
65
- /** @deprecated Alias of `failedPostings`. Remove once webc and app-ui are repointed. */
66
64
  resolveSchedules: JEScheduledTransactionWithFailedEntries[];
67
65
  revertStatusById: Record<JEScheduleKey | JEScheduleTransactionKey, FetchStateAndError>;
68
66
  scheduleCountsByTab: Partial<Record<JEPageTab, number>>;
@@ -28,10 +28,14 @@ export interface ExpenseAutomationTransactionViewSelector extends SelectorView {
28
28
  isAccountingProjectsEnabled: boolean;
29
29
  markAsNotMiscategorizedStatus: FetchStateAndError;
30
30
  /**
31
- * Parent tab badge counts, sourced from the listing response's
32
- * `parent_tab_total_count`. Used exclusively to drive the navbar / tab
33
- * strip badge labels — every other count consumer (pagination, in-list
34
- * "showing X of Y", save flows) keeps reading {@link totalCountByTab}.
31
+ * Tab badge counts under the filters currently applied to the list
32
+ * (transaction group + Completed sub-tab + search), so each badge matches
33
+ * the rows its tab renders. The active tab's entry is {@link totalCountByTab}
34
+ * itself, so it cannot drift when a cache hit skips the fetch; the inactive
35
+ * tab's comes from the listing response's `other_tab_total_count`. Used
36
+ * exclusively to drive the navbar / tab strip badge labels — every other
37
+ * count consumer (pagination, in-list "showing X of Y", save flows) keeps
38
+ * reading {@link totalCountByTab}.
35
39
  */
36
40
  parentTabTotalCountByTab: Record<TransactionsTab, number>;
37
41
  projectList: ProjectListSelectorView;
@@ -225,7 +225,7 @@ function getExpenseAutomationJESchedulesView(state) {
225
225
  const accruedSchedules = [];
226
226
  const oneTimeAccruals = [];
227
227
  const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
228
- const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJePostings, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
228
+ const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJeScheduleTransactionKeysByPeriodAndTab, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
229
229
  const accountSettingsView = (0, jeAccountSettingsViewSelector_1.getJEAccountSettingsView)(state);
230
230
  const newScheduleView = newSchedule.selectedDetailScheduleType === 'fixed_assets' ||
231
231
  newSchedule.selectedDetailScheduleType === 'prepaid_expenses'
@@ -264,11 +264,15 @@ function getExpenseAutomationJESchedulesView(state) {
264
264
  const jeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
265
265
  ? jeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
266
266
  : undefined;
267
+ const failedJeScheduleTransactionKeysForSelectedTab = selectedPeriodTabKey != null
268
+ ? failedJeScheduleTransactionKeysByPeriodAndTab[selectedPeriodTabKey]
269
+ : undefined;
267
270
  // Distinguishes "this tab has never been fetched for this period" from "fetched and genuinely
268
271
  // empty". Without it the page cannot tell a first visit from a real empty state, and renders an
269
272
  // empty table where it should render a skeleton.
270
273
  const hasLoadedForSelectedTab = jeScheduleTransactionKeysForSelectedTab != null;
271
274
  const jeScheduleTransactionKeys = jeScheduleTransactionKeysForSelectedTab ?? [];
275
+ const failedJeScheduleTransactionKeys = failedJeScheduleTransactionKeysForSelectedTab ?? [];
272
276
  const jeScheduleAccruedKeys = (selectedPeriodTabKey != null
273
277
  ? jeScheduleAccruedKeysByPeriodAndTab[selectedPeriodTabKey]
274
278
  : undefined) ?? [];
@@ -291,34 +295,24 @@ function getExpenseAutomationJESchedulesView(state) {
291
295
  accruedSchedules.push(accruedScheduleDetails);
292
296
  }
293
297
  });
294
- // Sourced from the tenant-wide bucket, not the per-period one: a failed posting belongs to no
295
- // close month, and windowing it is what kept older failures off the only tab that can resolve
296
- // them.
297
- failedJePostings.jeScheduleTransactionKeys.forEach((jeScheduleKey) => {
298
+ failedJeScheduleTransactionKeys.forEach((jeScheduleKey) => {
298
299
  const jeScheduleDetails = (0, jeSchedulesSelector_1.getJEScheduledTransactionByJEScheduleTransactionKey)(jeScheduleKey, state);
299
300
  failedJeScheduledTransaction.push(jeScheduleDetails);
300
301
  });
301
302
  const { sortKey, sortOrder, selectedJETypeFilter } = uiState;
302
- const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
303
- getJEScheduleRowType(schedule) === selectedJETypeFilter;
304
303
  const unsortedResolveSchedules = [];
305
304
  failedJeScheduledTransaction.forEach((schedule) => {
306
- // Only the entries that actually carry an error. The schedule's entry array is shared state:
307
- // opening a schedule's detail page or Quick View replaces it with every month the schedule
308
- // has, posted ones included, so fanning out over all of them turned one failed posting into a
309
- // row per month -- and a month that never failed has nothing to resolve, so it rendered with
310
- // an empty action column. Keying on `error` also makes the list self-correcting: an entry the
311
- // server no longer reports as failing drops out on the next fetch.
312
- schedule.scheduledJournalEntry
313
- .filter((journalEntry) => journalEntry.error.length > 0)
314
- .forEach((journalEntry) => {
305
+ schedule.scheduledJournalEntry.forEach((journalEntry) => {
315
306
  unsortedResolveSchedules.push({
316
307
  ...schedule,
317
308
  scheduledJournalEntry: journalEntry,
318
309
  });
319
310
  });
320
311
  });
321
- const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules.filter(matchesTypeFilter), sortKey, sortOrder);
312
+ const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules, sortKey, sortOrder);
313
+ const validResolveForPending = unsortedResolveSchedules.filter((r) => jeScheduleLocalDataById[r.scheduledJournalEntry.scheduledJournalEntryID] != null);
314
+ const matchesTypeFilter = (schedule) => selectedJETypeFilter == null ||
315
+ getJEScheduleRowType(schedule) === selectedJETypeFilter;
322
316
  const isCreatedStatus = (schedule) => {
323
317
  // An accrual is "created" once it is not review work: posted, reversing, reversed, or in a
324
318
  // transient posting claim.
@@ -336,6 +330,7 @@ function getExpenseAutomationJESchedulesView(state) {
336
330
  ];
337
331
  const pendingReviewSchedules = sortJEScheduledTransactions([
338
332
  ...allScheduleRows.filter((schedule) => isPendingReviewRow(schedule) && matchesTypeFilter(schedule)),
333
+ ...validResolveForPending,
339
334
  ], sortKey, sortOrder);
340
335
  const createdSchedules = sortJEScheduledTransactions(allScheduleRows.filter((schedule) => isCreatedStatus(schedule) && matchesTypeFilter(schedule)), sortKey, sortOrder);
341
336
  // KPI summary — derived from unfiltered schedules so counts are always accurate
@@ -454,9 +449,6 @@ function getExpenseAutomationJESchedulesView(state) {
454
449
  kpiSummary,
455
450
  pendingReviewSchedules,
456
451
  pendingReviewTotal,
457
- failedPostings: resolveSchedules,
458
- // Deprecated alias of failedPostings. Still read by the section's footer-form effect and by
459
- // app-ui analytics; remove once both are repointed.
460
452
  resolveSchedules: resolveSchedules,
461
453
  accountSettingsView,
462
454
  newScheduleView,
@@ -182,18 +182,35 @@ function getExpenseAutomationTransactionView(state) {
182
182
  review: monthYearPeriodId != null ? totalCountByReview[monthYearPeriodId] : 0,
183
183
  autoCategorized: monthYearPeriodId != null ? totalCountByAutoCat[monthYearPeriodId] : 0,
184
184
  };
185
- // Parent-tab badge counts. Sourced from `parent_tab_total_count` in the
186
- // listing response and used exclusively by the navbar / tab strip badges.
187
- // Independent of which Completed sub-tab is active so the badge stays
188
- // stable across sub-tab switches.
185
+ // Tab badge counts, used exclusively by the navbar / tab strip badges. Both
186
+ // tabs are counted under the filters applied to the list, so a badge always
187
+ // equals the number of rows that tab shows.
188
+ //
189
+ // The ACTIVE tab prefers its own list count: the two are the same number (the
190
+ // backend's parent_tab_total_count mirrors total_count), but `uiState.totalCount`
191
+ // is restored by every cache path that skips a fetch -- switching back to an
192
+ // already-loaded period, or to a cached Completed sub-tab -- whereas the stored
193
+ // badge is only written when a response lands, so on those paths it would keep
194
+ // showing whatever was fetched last.
195
+ //
196
+ // The `in` check is load-bearing, not defensive: `totalCount` is a per-period
197
+ // map typed as `Record<MonthYearPeriodId, number>`, so indexing it is typed
198
+ // `number` but is `undefined` for any period the active (sub-)tab has not
199
+ // loaded -- the window between switching to a fresh sub-tab and its response
200
+ // landing. Falling back to the stored badge there keeps a real number in the
201
+ // label instead of blanking it.
189
202
  const parentTotalCountByTab = expenseAutomationTransactionsViewState.parentTotalCountByTab;
203
+ const storedBadgeByTab = (tab) => monthYearPeriodId != null
204
+ ? (parentTotalCountByTab[tab][monthYearPeriodId] ?? 0)
205
+ : 0;
206
+ const badgeForTab = (tab, listCountByPeriod) => selectedTransactionCategorizationTab === tab &&
207
+ monthYearPeriodId != null &&
208
+ monthYearPeriodId in listCountByPeriod
209
+ ? listCountByPeriod[monthYearPeriodId]
210
+ : storedBadgeByTab(tab);
190
211
  const parentTabTotalCountByTab = {
191
- review: monthYearPeriodId != null
192
- ? (parentTotalCountByTab.review[monthYearPeriodId] ?? 0)
193
- : 0,
194
- autoCategorized: monthYearPeriodId != null
195
- ? (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
196
- : 0,
212
+ review: badgeForTab('review', totalCountByReview),
213
+ autoCategorized: badgeForTab('autoCategorized', totalCountByAutoCat),
197
214
  };
198
215
  const fetchStateByTab = {
199
216
  review: {