@zeniai/client-epic-state 4.20.2 → 4.20.3-beta10ND

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 (175) hide show
  1. package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.d.ts +19 -0
  2. package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.js +2 -0
  3. package/lib/commonStateTypes/animations.d.ts +1 -1
  4. package/lib/commonStateTypes/animations.js +3 -0
  5. package/lib/entity/aiCfo/aiCfoSelector.d.ts +1 -2
  6. package/lib/entity/billPay/billTransaction/billTransactionState.d.ts +2 -2
  7. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +38 -0
  8. package/lib/entity/jeSchedules/jeSchedulesPayload.js +78 -0
  9. package/lib/entity/jeSchedules/jeSchedulesSelector.d.ts +4 -1
  10. package/lib/entity/jeSchedules/jeSchedulesSelector.js +5 -1
  11. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +37 -0
  12. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  13. package/lib/entity/snackbar/snackbarTypes.js +5 -0
  14. package/lib/entity/tenant/tenantPayload.d.ts +1 -0
  15. package/lib/entity/tenant/tenantReducer.js +1 -0
  16. package/lib/entity/tenant/tenantSelector.d.ts +1 -0
  17. package/lib/entity/tenant/tenantSelector.js +9 -1
  18. package/lib/entity/tenant/tenantState.d.ts +1 -0
  19. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.d.ts +4 -1
  20. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.js +1 -0
  21. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +3 -0
  22. package/lib/entity/transaction/payloadTypes/transactionPayload.js +17 -1
  23. package/lib/entity/transaction/stateTypes/scheduleTransaction.d.ts +1 -0
  24. package/lib/entity/transaction/stateTypes/transaction.d.ts +5 -0
  25. package/lib/entity/transaction/stateTypes/transactionLine.d.ts +1 -1
  26. package/lib/epic.d.ts +8 -1
  27. package/lib/epic.js +8 -1
  28. package/lib/esm/common/aiCfo/aiCfoSuggestedQuestionsPageContext.js +1 -0
  29. package/lib/esm/commonStateTypes/animations.js +3 -0
  30. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +78 -0
  31. package/lib/esm/entity/jeSchedules/jeSchedulesSelector.js +5 -1
  32. package/lib/esm/entity/snackbar/snackbarTypes.js +5 -0
  33. package/lib/esm/entity/tenant/tenantReducer.js +1 -0
  34. package/lib/esm/entity/tenant/tenantSelector.js +7 -0
  35. package/lib/esm/entity/transaction/payloadTypes/scheduleTransactionPayload.js +1 -0
  36. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +17 -1
  37. package/lib/esm/epic.js +8 -1
  38. package/lib/esm/index.js +10 -7
  39. package/lib/esm/reducer.js +3 -0
  40. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +82 -1
  41. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +8 -2
  42. package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +29 -0
  43. package/lib/esm/view/classList/fetchClassListEpic.js +9 -2
  44. package/lib/esm/view/commonVendorView/vendorView/vendorViewSelector.js +18 -5
  45. package/lib/esm/view/commonVendorView/vendorsTabVendorView/vendorsTabVendorViewSelector.js +6 -2
  46. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +2 -2
  47. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +2 -2
  48. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +4 -3
  49. package/lib/esm/view/expenseAutomationView/expenseAutomationViewSelector.js +0 -1
  50. package/lib/esm/view/expenseAutomationView/helpers/saveTransactionHelper.js +2 -2
  51. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +2 -2
  52. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +17 -1
  53. package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +10 -2
  54. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +63 -6
  55. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +12 -4
  56. package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +22 -9
  57. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +12 -6
  58. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +18 -1
  59. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +18 -1
  60. package/lib/esm/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +17 -14
  61. package/lib/esm/view/spendManagement/autotransferRules/autoTransferRulesPayload.js +26 -0
  62. package/lib/esm/view/spendManagement/autotransferRules/autoTransferRulesReducer.js +199 -0
  63. package/lib/esm/view/spendManagement/autotransferRules/autoTransferRulesSelector.js +52 -0
  64. package/lib/esm/view/spendManagement/autotransferRules/autoTransferRulesState.js +1 -0
  65. package/lib/esm/view/spendManagement/autotransferRules/epics/createAutoTransferRuleEpic.js +99 -0
  66. package/lib/esm/view/spendManagement/autotransferRules/epics/deleteAutoTransferRuleEpic.js +48 -0
  67. package/lib/esm/view/spendManagement/autotransferRules/epics/fetchAutoTransferReviewDetailEpic.js +36 -0
  68. package/lib/esm/view/spendManagement/autotransferRules/epics/fetchAutoTransferRuleHistory.js +45 -0
  69. package/lib/esm/view/spendManagement/autotransferRules/epics/fetchAutoTransferRulesEpic.js +50 -0
  70. package/lib/esm/view/spendManagement/autotransferRules/epics/updateAutoTransferRuleEpic.js +69 -0
  71. package/lib/esm/view/spendManagement/billPay/billList/billListSelector.js +10 -0
  72. package/lib/esm/view/spendManagement/billPay/billList/billListState.js +1 -0
  73. package/lib/esm/view/spendManagement/billPay/billPayReview/billPayReviewSelector.js +7 -3
  74. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +5 -5
  75. package/lib/esm/view/spendManagement/billPay/billPaySetupApproverView/epic/fetchBillPayApproversDetailsEpic.js +7 -2
  76. package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +13 -6
  77. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +1 -0
  78. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +2 -0
  79. package/lib/esm/view/spendManagement/reimbursement/editRemiView/editRemiViewSelector.js +7 -4
  80. package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListSelector.js +12 -0
  81. package/lib/esm/view/spendManagement/reimbursement/remiListView/remiListState.js +1 -0
  82. package/lib/esm/view/spendManagement/treasury/treasuryList/epics/fetchTreasuryDetailEpic.js +2 -2
  83. package/lib/esm/view/spendManagement/treasury/treasuryList/treasuryDetailReducer.js +2 -1
  84. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
  85. package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +2 -2
  86. package/lib/esm/view/transactionDetail/transactionDetailLocalDataHelper.js +16 -14
  87. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +9 -2
  88. package/lib/index.d.ts +19 -12
  89. package/lib/index.js +54 -32
  90. package/lib/reducer.d.ts +3 -0
  91. package/lib/reducer.js +3 -0
  92. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  93. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +7 -0
  94. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +15 -1
  95. package/lib/view/aiCfoView/aiCfoViewReducer.js +83 -2
  96. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +4 -1
  97. package/lib/view/aiCfoView/aiCfoViewSelector.js +9 -2
  98. package/lib/view/aiCfoView/aiCfoViewState.d.ts +15 -1
  99. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +8 -0
  100. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +33 -0
  101. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  102. package/lib/view/classList/fetchClassListEpic.d.ts +1 -1
  103. package/lib/view/classList/fetchClassListEpic.js +8 -1
  104. package/lib/view/commonVendorView/vendorView/vendorViewSelector.d.ts +1 -0
  105. package/lib/view/commonVendorView/vendorView/vendorViewSelector.js +18 -5
  106. package/lib/view/commonVendorView/vendorsTabVendorView/vendorsTabVendorViewSelector.d.ts +1 -0
  107. package/lib/view/commonVendorView/vendorsTabVendorView/vendorsTabVendorViewSelector.js +6 -2
  108. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +2 -2
  109. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +1 -1
  110. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +4 -3
  111. package/lib/view/expenseAutomationView/expenseAutomationViewSelector.js +0 -1
  112. package/lib/view/expenseAutomationView/helpers/saveTransactionHelper.js +2 -2
  113. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  114. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +2 -2
  115. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +1 -1
  116. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +2 -2
  117. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +18 -2
  118. package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +2 -0
  119. package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +10 -2
  120. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +63 -6
  121. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +12 -4
  122. package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +22 -9
  123. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +11 -5
  124. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +5 -0
  125. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +20 -0
  126. package/lib/view/onboardingView/cockpitView/types/onboardingCockpitViewTypes.d.ts +1 -1
  127. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +2 -0
  128. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +19 -2
  129. package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +17 -14
  130. package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
  131. package/lib/view/spendManagement/autotransferRules/autoTransferRulesPayload.d.ts +75 -0
  132. package/lib/view/spendManagement/autotransferRules/autoTransferRulesPayload.js +30 -0
  133. package/lib/view/spendManagement/autotransferRules/autoTransferRulesReducer.d.ts +50 -0
  134. package/lib/view/spendManagement/autotransferRules/autoTransferRulesReducer.js +206 -0
  135. package/lib/view/spendManagement/autotransferRules/autoTransferRulesSelector.d.ts +24 -0
  136. package/lib/view/spendManagement/autotransferRules/autoTransferRulesSelector.js +61 -0
  137. package/lib/view/spendManagement/autotransferRules/autoTransferRulesState.d.ts +38 -0
  138. package/lib/view/spendManagement/autotransferRules/autoTransferRulesState.js +2 -0
  139. package/lib/view/spendManagement/autotransferRules/epics/createAutoTransferRuleEpic.d.ts +12 -0
  140. package/lib/view/spendManagement/autotransferRules/epics/createAutoTransferRuleEpic.js +105 -0
  141. package/lib/view/spendManagement/autotransferRules/epics/deleteAutoTransferRuleEpic.d.ts +8 -0
  142. package/lib/view/spendManagement/autotransferRules/epics/deleteAutoTransferRuleEpic.js +52 -0
  143. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferReviewDetailEpic.d.ts +7 -0
  144. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferReviewDetailEpic.js +40 -0
  145. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferRuleHistory.d.ts +7 -0
  146. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferRuleHistory.js +52 -0
  147. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferRulesEpic.d.ts +10 -0
  148. package/lib/view/spendManagement/autotransferRules/epics/fetchAutoTransferRulesEpic.js +54 -0
  149. package/lib/view/spendManagement/autotransferRules/epics/updateAutoTransferRuleEpic.d.ts +8 -0
  150. package/lib/view/spendManagement/autotransferRules/epics/updateAutoTransferRuleEpic.js +73 -0
  151. package/lib/view/spendManagement/billPay/billList/billListSelector.js +10 -0
  152. package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
  153. package/lib/view/spendManagement/billPay/billList/billListState.js +1 -0
  154. package/lib/view/spendManagement/billPay/billPayReview/billPayReviewSelector.js +7 -3
  155. package/lib/view/spendManagement/billPay/billPaySetupApproverView/billPaySetupApproverViewSelector.js +5 -5
  156. package/lib/view/spendManagement/billPay/billPaySetupApproverView/epic/fetchBillPayApproversDetailsEpic.js +7 -2
  157. package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +13 -6
  158. package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetail.d.ts +1 -1
  159. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  160. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.js +1 -0
  161. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +2 -0
  162. package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewSelector.js +6 -3
  163. package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.d.ts +1 -0
  164. package/lib/view/spendManagement/reimbursement/remiListView/remiListSelector.js +12 -0
  165. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
  166. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.js +1 -0
  167. package/lib/view/spendManagement/treasury/treasuryList/epics/fetchTreasuryDetailEpic.js +2 -2
  168. package/lib/view/spendManagement/treasury/treasuryList/treasuryDetailReducer.d.ts +2 -1
  169. package/lib/view/spendManagement/treasury/treasuryList/treasuryDetailReducer.js +2 -1
  170. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +2 -2
  171. package/lib/view/transactionDetail/epics/saveTransactionHelper.js +2 -2
  172. package/lib/view/transactionDetail/transactionDetailLocalDataHelper.js +16 -14
  173. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +1 -0
  174. package/lib/view/transactionDetail/transactionDetailSelector.js +9 -2
  175. package/package.json +1 -1
@@ -25,7 +25,7 @@ export const pusherBatchStatusCompletionEpic = (actions$) => actions$.pipe(filte
25
25
  * force `phase` to `completed` (dismiss automatching banner) and refresh the batch list.
26
26
  * Cancels when the batch completes normally, bulk state is cleared, or another upload supersedes.
27
27
  */
28
- export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), mergeMap((action) => {
28
+ export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), switchMap((action) => {
29
29
  const { batchId } = action.payload;
30
30
  return timer(BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS).pipe(mergeMap(() => {
31
31
  const bulk = state$.value.expenseAutomationMissingReceiptsViewState.bulkUpload;
@@ -44,10 +44,11 @@ export const bulkUploadAutomatchingTimeoutEpic = (actions$, state$) => actions$.
44
44
  * error snackbar per upload session (first failure only) so the user is not spammed every
45
45
  * interval; Pusher or a later successful poll still completes the flow.
46
46
  */
47
- export const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), mergeMap((action) => {
47
+ export const pollBulkUploadBatchStatusEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUploadReceiptsSuccess.match), switchMap((action) => {
48
48
  const { batchId } = action.payload;
49
49
  let pollErrorNotified = false;
50
- return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(bulkUploadAutomatchingTimedOut.match), filter((action) => action.payload.batchId === batchId)))), switchMap(() => zeniAPI
50
+ return timer(FALLBACK_FIRST_DELAY_MS, FALLBACK_POLL_INTERVAL_MS).pipe(takeUntil(merge(actions$.pipe(filter(clearBulkUpload.match)), actions$.pipe(filter(pusherBatchStatusUpdate.match), filter((action) => action.payload.batchId === batchId &&
51
+ action.payload.status === 'completed')), actions$.pipe(filter(fetchBulkUploadBatchDetailsSuccess.match), filter((action) => action.payload.batchId === batchId)), actions$.pipe(filter(bulkUploadAutomatchingTimedOut.match), filter((action) => action.payload.batchId === batchId)))), switchMap(() => zeniAPI
51
52
  .getJSON(`${zeniAPI.apiEndPoints.communicationAgentMicroServiceBaseUrl}/1.0/batches/${batchId}`)
52
53
  .pipe(mergeMap((response) => {
53
54
  /** Same batch-details URL; polls until `status` is completed (Pusher may win first). */
@@ -91,7 +91,6 @@ export function getExpenseAutomationView(state) {
91
91
  const fetchStateVariables = [
92
92
  expenseAutomationMissingReceiptsViewState,
93
93
  expenseAutomationJESchedulesViewState,
94
- monthEndCloseChecksView,
95
94
  expenseAutomationTransactionsView,
96
95
  expenseAutomationReconciliationViewState,
97
96
  ];
@@ -64,8 +64,8 @@ export const toTransactionUpdatesFromTransactionCategorizationLocalData = (trans
64
64
  lineItem.account?.qboId !== accountLine.account.qboId &&
65
65
  Boolean(lineItem.account?.qboId);
66
66
  hasClassChanged =
67
- Boolean(lineItem.class?.qboId) &&
68
- lineItem.class?.qboId !== accountLine.class.qboId;
67
+ (lineItem.class?.qboId != null || accountLine.class?.qboId != null) &&
68
+ lineItem.class?.qboId !== accountLine.class?.qboId;
69
69
  const recommendedAccountBase = toRecommendedAccountBase(lineItem.amount.amount, lineItem.account);
70
70
  const recommendedClassBase = toRecommendedClassBase(lineItem.amount.amount, lineItem.class);
71
71
  if (entityDetails != null &&
@@ -234,7 +234,7 @@ const buildLineItemById = (transaction, uncategorizedIncomeExpense, recommendati
234
234
  isPreFilled: true,
235
235
  };
236
236
  }
237
- if (accountLine.class.classId === '' &&
237
+ if (Boolean(accountLine.class?.classId) === false &&
238
238
  higherPreferenceRecommendation?.class != null) {
239
239
  record.class = {
240
240
  ...higherPreferenceRecommendation.class,
@@ -464,7 +464,7 @@ export const setEntityRecommendationForLineIdInLocalData = (draft, transaction,
464
464
  }
465
465
  : accountLine.account;
466
466
  record.class =
467
- accountLine.class.classId !== ''
467
+ Boolean(accountLine.class?.classId) !== false
468
468
  ? accountLine.class
469
469
  : recommendations?.[0]?.class
470
470
  ? {
@@ -44,6 +44,8 @@ export const initialState = {
44
44
  uiState: {
45
45
  searchString: '',
46
46
  scrollPosition: { scrollTop: 0, scrollLeft: undefined },
47
+ sortKey: 'startMonth',
48
+ sortOrder: 'descending',
47
49
  totalCount: 0,
48
50
  limit: 10,
49
51
  },
@@ -365,12 +367,26 @@ const expenseAutomationJESchedulesView = createSlice({
365
367
  clearJeAccountSettingsLocalData(draft) {
366
368
  draft.accountSettings.localData = accountSettingsInitialState.localData;
367
369
  },
370
+ updateJESchedulesUIState(draft, action) {
371
+ if (action.payload.sortKey != null) {
372
+ draft.uiState.sortKey = action.payload.sortKey;
373
+ }
374
+ if (action.payload.sortOrder != null) {
375
+ draft.uiState.sortOrder = action.payload.sortOrder;
376
+ }
377
+ if (action.payload.searchString != null) {
378
+ draft.uiState.searchString = action.payload.searchString;
379
+ }
380
+ if (action.payload.scrollPosition != null) {
381
+ draft.uiState.scrollPosition = action.payload.scrollPosition;
382
+ }
383
+ },
368
384
  clearExpenseAutomationJESchedulesView(draft) {
369
385
  Object.assign(draft, initialState);
370
386
  },
371
387
  },
372
388
  });
373
- export const { clearExpenseAutomationJESchedulesView, clearJeAccountSettingsLocalData, clearJeScheduleLocalData, fetchAccountSettingsListForAccountTypes, fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesPage, fetchJeSchedulesSuccess, fetchRecommendationForAccountSettings, ignoreRecommendedJeSchedule, ignoreRecommendedJeScheduleFailure, ignoreRecommendedJeScheduleSuccess, initializeAccountSettingsView, initializeJeScheduleLocalData, removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, removeJeScheduleTransactionKey, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, saveAccountSettings, saveAccountSettingsFailure, saveAccountSettingsLocalData, saveAccountSettingsSuccess, updateAccountSettingsListForAccountTypes, updateAccountSettingsListForAccountTypesFailure, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, updateRecommendationForAccountSettings, updateRecommendationForAccountSettingsFailure, } = expenseAutomationJESchedulesView.actions;
389
+ export const { clearExpenseAutomationJESchedulesView, clearJeAccountSettingsLocalData, clearJeScheduleLocalData, fetchAccountSettingsListForAccountTypes, fetchJeSchedules, fetchJeSchedulesFailure, fetchJeSchedulesPage, fetchJeSchedulesSuccess, fetchRecommendationForAccountSettings, ignoreRecommendedJeSchedule, ignoreRecommendedJeScheduleFailure, ignoreRecommendedJeScheduleSuccess, initializeAccountSettingsView, initializeJeScheduleLocalData, removeFailedJeScheduleTransactionKey, removeJeScheduleLocalDataById, removeJeScheduleTransactionKey, retryJeSchedule, retryJeScheduleFailure, retryJeScheduleSuccess, saveAccountSettings, saveAccountSettingsFailure, saveAccountSettingsLocalData, saveAccountSettingsSuccess, updateAccountSettingsListForAccountTypes, updateAccountSettingsListForAccountTypesFailure, updateJESchedulesUIState, updateJeScheduleLocalDataById, updateJeScheduleTransactionKeys, updateRecommendationForAccountSettings, updateRecommendationForAccountSettingsFailure, } = expenseAutomationJESchedulesView.actions;
374
390
  export default expenseAutomationJESchedulesView.reducer;
375
391
  const doUpdateRecommendationForAccountSettings = (draft, payload) => {
376
392
  const { prepaidExpensesRecommendations, fixedAssetsRecommendations, accruedExpensesRecommendations, } = mapAccountTypeRecommendationPayloadToAccountRecommendationByType(payload);
@@ -1,3 +1,4 @@
1
+ import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
1
2
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
2
3
  import { getAccountBase } from '../../../entity/account/accountSelector';
3
4
  import { getClassById } from '../../../entity/class/classSelector';
@@ -6,7 +7,7 @@ import { getUserByUserId } from '../../../entity/user/userSelector';
6
7
  import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
7
8
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
8
9
  export function getExpenseAutomationFluxAnalysisView(state) {
9
- const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState } = state;
10
+ const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
10
11
  const { fetchState, error, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
11
12
  const fetchStateAndError = {
12
13
  fetchState,
@@ -91,10 +92,17 @@ export function getExpenseAutomationFluxAnalysisView(state) {
91
92
  },
92
93
  };
93
94
  const completionStatus = fluxCompletionStatus != null ? fluxCompletionStatus : 'incomplete';
95
+ const monthEndFetchState = monthYearPeriodId != null
96
+ ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
97
+ : { fetchState: 'Not-Started', error: undefined };
98
+ const reducedFetchStatus = reduceAnyFetchState([
99
+ fetchStateAndError,
100
+ monthEndFetchState,
101
+ ]);
94
102
  return {
95
103
  sections,
96
104
  totalBalancesAndVariance,
97
- fetchStatus: fetchStateAndError,
105
+ fetchStatus: reducedFetchStatus,
98
106
  bulkReviewStatus,
99
107
  reviewOperatingExpensesIds,
100
108
  selectedSectionIds,
@@ -1,4 +1,6 @@
1
1
  import omit from 'lodash/omit';
2
+ import orderBy from 'lodash/orderBy';
3
+ import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
2
4
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
5
  import { getAccountIdsForTypes } from '../../../entity/account/accountSelector';
4
6
  import { getJEScheduledTransactionByJEScheduleTransactionKey, } from '../../../entity/jeSchedules/jeSchedulesSelector';
@@ -10,10 +12,48 @@ import { filterNestedAccountHierarchyById } from '../../scheduleView/scheduleDet
10
12
  import { getAccountLabelForScheduleType, getAccountsTypesForScheduleList, } from '../../scheduleView/scheduleListView/scheduleListHelper';
11
13
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
12
14
  import { getJEAccountSettingsView } from './jeAccountSettingsViewSelector';
15
+ function getJEScheduleSortAccessor(sortKey) {
16
+ switch (sortKey) {
17
+ case 'vendor':
18
+ return (s) => s.vendor.name?.toLowerCase();
19
+ case 'category':
20
+ return (s) => s.jeDebit.account?.accountName?.toLowerCase();
21
+ case 'class':
22
+ return (s) => s.jeDebit.accountingClass?.className?.toLowerCase();
23
+ case 'depCategory':
24
+ return (s) => s.jeCredit.account?.accountName?.toLowerCase();
25
+ case 'scheduleCategory':
26
+ return (s) => s.jeScheduleType;
27
+ case 'startMonth':
28
+ return (s) => s.startDate?.valueOf();
29
+ case 'type':
30
+ return (s) => s.baseTransaction.typeOfTransaction;
31
+ case 'amortizationPeriod':
32
+ return (s) => s.period;
33
+ case 'jePostingDate':
34
+ return (s) => s.dayOfPostingDate;
35
+ case 'remainingMonths':
36
+ return (s) => s.period;
37
+ case 'runningBalance':
38
+ return (s) => s.balanceAsOfToday?.amount;
39
+ case 'totalAmount':
40
+ return (s) => s.baseTransaction.amount.amount;
41
+ case 'transactionDate':
42
+ return (s) => s.baseTransaction.date.valueOf();
43
+ case 'memo':
44
+ return (s) => s.baseTransaction.memo?.toLowerCase();
45
+ default:
46
+ return (s) => s.startDate?.valueOf();
47
+ }
48
+ }
49
+ function sortJEScheduledTransactions(transactions, sortKey, sortOrder) {
50
+ const accessor = getJEScheduleSortAccessor(sortKey);
51
+ return orderBy(transactions, [accessor], [sortOrder === 'ascending' ? 'asc' : 'desc']);
52
+ }
13
53
  export function getExpenseAutomationJESchedulesView(state) {
14
54
  const jeScheduledTransaction = [];
15
55
  const failedJeScheduledTransaction = [];
16
- const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
56
+ const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
17
57
  const { jeScheduleTransactionKeysByPeriod, failedJeScheduleTransactionKeysByPeriod, jeScheduleLocalDataById, postStatusById, ignoreStatusById, uiState, error, fetchState, refreshStatus, } = expenseAutomationJESchedulesViewState;
18
58
  const accountSettingsView = getJEAccountSettingsView(state);
19
59
  const currentTenant = getCurrentTenant(state);
@@ -59,18 +99,33 @@ export function getExpenseAutomationJESchedulesView(state) {
59
99
  const jeScheduleDetails = getJEScheduledTransactionByJEScheduleTransactionKey(jeScheduleKey, state);
60
100
  failedJeScheduledTransaction.push(jeScheduleDetails);
61
101
  });
62
- const draftSchedules = jeScheduledTransaction.filter((schedule) => schedule.status.code === 'draft');
63
- const resolveSchedules = [];
102
+ const { sortKey, sortOrder } = uiState;
103
+ const draftSchedules = sortJEScheduledTransactions(jeScheduledTransaction.filter((schedule) => schedule.status.code === 'draft'), sortKey, sortOrder);
104
+ const ongoingSchedules = sortJEScheduledTransactions(jeScheduledTransaction.filter((schedule) => schedule.status.code === 'ongoing'), sortKey, sortOrder);
105
+ const completedSchedules = sortJEScheduledTransactions(jeScheduledTransaction.filter((schedule) => schedule.status.code === 'completed' ||
106
+ schedule.status.code === 'marked_as_completed'), sortKey, sortOrder);
107
+ const unsortedResolveSchedules = [];
64
108
  failedJeScheduledTransaction.forEach((schedule) => {
65
109
  schedule.scheduledJournalEntry.forEach((journalEntry) => {
66
- resolveSchedules.push({ ...schedule, scheduledJournalEntry: journalEntry });
110
+ unsortedResolveSchedules.push({
111
+ ...schedule,
112
+ scheduledJournalEntry: journalEntry,
113
+ });
67
114
  });
68
115
  });
116
+ const resolveSchedules = sortJEScheduledTransactions(unsortedResolveSchedules, sortKey, sortOrder);
69
117
  const allSteps = monthYearPeriodId != null
70
118
  ? getAllSteps(monthEndCloseChecksState, monthYearPeriodId, currentTenant.tenantId)
71
119
  : [];
72
120
  const jeCompletionStatus = allSteps.find((step) => step.step === 'je_schedules')?.completionStatus;
73
121
  const completionStatus = jeCompletionStatus != null ? jeCompletionStatus : 'incomplete';
122
+ const monthEndFetchState = monthYearPeriodId != null
123
+ ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
124
+ : { fetchState: 'Not-Started', error: undefined };
125
+ const reducedFetchStatus = reduceAnyFetchState([
126
+ { fetchState, error },
127
+ monthEndFetchState,
128
+ ]);
74
129
  return {
75
130
  uncategorizedAccounts,
76
131
  allDepreciationAccountList: filteredDepAccounts,
@@ -79,15 +134,17 @@ export function getExpenseAutomationJESchedulesView(state) {
79
134
  allAccountList: filteredAccounts,
80
135
  accountListNestedAccountHierarchy,
81
136
  allClassList: allClasses,
137
+ completedSchedules,
82
138
  draftSchedules,
139
+ ongoingSchedules,
83
140
  resolveSchedules: resolveSchedules,
84
141
  accountSettingsView,
85
142
  postStatusById: postStatusById,
86
143
  ignoreStatusById: ignoreStatusById,
87
- fetchState: fetchState,
144
+ fetchState: reducedFetchStatus.fetchState,
88
145
  jeScheduleLocalDataById: jeScheduleLocalDataById,
89
146
  uiState: uiState,
90
- error: error,
147
+ error: reducedFetchStatus.error,
91
148
  refreshStatus,
92
149
  completionStatus,
93
150
  };
@@ -1,4 +1,5 @@
1
1
  import orderBy from 'lodash/orderBy';
2
+ import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
2
3
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
3
4
  import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
4
5
  import { getSupportedTransactionById, getSupportedTransactionsByIds, } from '../../../entity/transaction/transactionSelector';
@@ -7,7 +8,7 @@ import { getCompletedTransactionsCacheKey } from '../reducers/missingReceiptsVie
7
8
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
8
9
  import { isUnmatchedTabFileStatus, } from '../types/missingReceiptsViewState';
9
10
  export function getExpenseAutomationMissingReceiptsView(state) {
10
- const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
11
+ const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
11
12
  const currentTenant = getCurrentTenant(state);
12
13
  const { selectedPeriodByTenantId } = expenseAutomationViewState;
13
14
  const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
@@ -36,7 +37,7 @@ export function getExpenseAutomationMissingReceiptsView(state) {
36
37
  transaction.lines.length > 0 &&
37
38
  transaction.lines[0]
38
39
  ?.class != null
39
- ? transaction.lines[0].class.className.toLowerCase()
40
+ ? transaction.lines[0].class?.className.toLowerCase()
40
41
  : null;
41
42
  case 'vendor':
42
43
  default:
@@ -175,9 +176,16 @@ export function getExpenseAutomationMissingReceiptsView(state) {
175
176
  vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
176
177
  };
177
178
  });
179
+ const monthEndFetchState = monthYearPeriodId != null
180
+ ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
181
+ : { fetchState: 'Not-Started', error: undefined };
182
+ const reducedFetchStatus = reduceAnyFetchState([
183
+ { fetchState, error },
184
+ monthEndFetchState,
185
+ ]);
178
186
  return {
179
- fetchState,
180
- error,
187
+ fetchState: reducedFetchStatus.fetchState,
188
+ error: reducedFetchStatus.error,
181
189
  uploadReceiptStatusById,
182
190
  uiState,
183
191
  refreshStatus,
@@ -13,7 +13,7 @@ import { getAccountList, getNestedAccountListHierarchy, } from '../../accountLis
13
13
  import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
14
14
  import { initialActionFetchState, initialReconciliationTabsState, initialState, } from '../reducers/reconciliationViewReducer';
15
15
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
16
- export const getExpenseAutomationReconciliationView = createSelector((state) => state, (state) => getCurrentTenant(state), (state) => state.expenseAutomationReconciliationViewState, (state) => state.expenseAutomationViewState, (state) => state.plaidAccountViewState, (state) => state.accountListState, (state) => state.accountState, (state) => state.classListState, (state) => state.classState, (state) => state.monthEndCloseChecksState, (state) => state.vendorState, (state, currentTenant, reconciliationViewState, expenseAutomationViewState, plaidAccountViewState, accountListState, accountState, classListState, classState, monthEndCloseChecksState, vendorState) => {
16
+ export const getExpenseAutomationReconciliationView = createSelector((state) => state, (state) => getCurrentTenant(state), (state) => state.expenseAutomationReconciliationViewState, (state) => state.expenseAutomationViewState, (state) => state.plaidAccountViewState, (state) => state.accountListState, (state) => state.accountState, (state) => state.classListState, (state) => state.classState, (state) => state.monthEndCloseChecksState, (state) => state.vendorState, (state) => state.monthEndCloseChecksViewState, (state, currentTenant, reconciliationViewState, expenseAutomationViewState, plaidAccountViewState, accountListState, accountState, classListState, classState, monthEndCloseChecksState, vendorState, monthEndCloseChecksViewState) => {
17
17
  const { selectedPeriodByTenantId } = expenseAutomationViewState;
18
18
  const reconcileTabUiState = reconciliationViewState.reconTabsState.reconcile.uiState;
19
19
  const reviewTabUiState = reconciliationViewState.reconTabsState.review.uiState;
@@ -35,6 +35,13 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
35
35
  }
36
36
  return acc;
37
37
  }, []);
38
+ const monthYearPeriodId = selectedPeriod != null ? toMonthYearPeriodId(selectedPeriod) : null;
39
+ const monthEndFetchState = monthYearPeriodId != null
40
+ ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? {
41
+ fetchState: 'Not-Started',
42
+ error: undefined,
43
+ })
44
+ : { fetchState: 'Not-Started', error: undefined };
38
45
  if (accountReconForMonthYearPeriod == null) {
39
46
  return {
40
47
  bankAccounts: [],
@@ -44,10 +51,13 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
44
51
  classListNestedAccountHierarchy: [],
45
52
  allAccountList: [],
46
53
  allClassList: [],
47
- fetchStatus: {
48
- fetchState: reconciliationViewState.fetchState,
49
- error: reconciliationViewState.error,
50
- },
54
+ fetchStatus: reduceAnyFetchState([
55
+ {
56
+ fetchState: reconciliationViewState.fetchState,
57
+ error: reconciliationViewState.error,
58
+ },
59
+ monthEndFetchState,
60
+ ]),
51
61
  plaidConnectionDetails: plaidAccountViewState['expense_automation_reconcile']
52
62
  .plaidConnectionDetails,
53
63
  completionStatus: 'incomplete',
@@ -270,10 +280,13 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
270
280
  bankAccounts: uniqueBankAccounts,
271
281
  creditCards: uniqueCreditCards,
272
282
  accountReconciliationsByAccountID: reconList,
273
- fetchStatus: {
274
- fetchState: reconciliationViewState.fetchState,
275
- error: reconciliationViewState.error,
276
- },
283
+ fetchStatus: reduceAnyFetchState([
284
+ {
285
+ fetchState: reconciliationViewState.fetchState,
286
+ error: reconciliationViewState.error,
287
+ },
288
+ monthEndFetchState,
289
+ ]),
277
290
  plaidConnectionDetails: plaidAccountViewState['expense_automation_reconcile']
278
291
  .plaidConnectionDetails,
279
292
  reconciliationTabsState: reconciliationViewState.reconTabsState,
@@ -1,5 +1,5 @@
1
1
  import omit from 'lodash/omit';
2
- import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
2
+ import { reduceAllFetchState, reduceAnyFetchState, } from '../../../commonStateTypes/reduceFetchState';
3
3
  import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
5
5
  import { getTransactionWithCOT } from '../../../entity/transaction/transactionHelper';
@@ -8,7 +8,7 @@ import { getAccountList, getNestedAccountListHierarchy, getUncategorizedAccounts
8
8
  import { getClassList, getNestedClassListHierarchy, } from '../../classList/classListSelector';
9
9
  import { getAllSteps } from '../selectorTypes/expenseAutomationViewSelectorTypes';
10
10
  export function getExpenseAutomationTransactionView(state) {
11
- const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
11
+ const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
12
12
  const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
13
13
  const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
14
14
  const uncategorizedIncomeExpense = getUncategorizedAccounts(accountState, accountListState, 'accountList');
@@ -41,10 +41,16 @@ export function getExpenseAutomationTransactionView(state) {
41
41
  .filter((transaction) => transaction != null);
42
42
  const transactions = getSupportedTransactionsByIds(transactionState, transactionIds);
43
43
  const transactionsWithCOT = transactions.map((transaction) => getTransactionWithCOT(transaction));
44
- const fetchStatus = reduceAllFetchState([
45
- accountList,
46
- classList,
47
- expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab],
44
+ const monthEndFetchState = monthYearPeriodId != null
45
+ ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
46
+ : { fetchState: 'Not-Started', error: undefined };
47
+ const fetchStatus = reduceAnyFetchState([
48
+ reduceAllFetchState([
49
+ accountList,
50
+ classList,
51
+ expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab],
52
+ ]),
53
+ monthEndFetchState,
48
54
  ]);
49
55
  const totalCountByReview = expenseAutomationTransactionsViewState.transactionCategorizationView.review
50
56
  .uiState.totalCount;
@@ -1 +1,18 @@
1
- export {};
1
+ import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
+ const JE_SCHEDULE_SORT_KEYS = [
3
+ 'vendor',
4
+ 'category',
5
+ 'class',
6
+ 'depCategory',
7
+ 'scheduleCategory',
8
+ 'startMonth',
9
+ 'type',
10
+ 'amortizationPeriod',
11
+ 'jePostingDate',
12
+ 'remainingMonths',
13
+ 'runningBalance',
14
+ 'totalAmount',
15
+ 'transactionDate',
16
+ 'memo',
17
+ ];
18
+ export const toJEScheduleSortKey = (v) => stringToUnion(v, JE_SCHEDULE_SORT_KEYS);
@@ -3,7 +3,10 @@ import { getSummationFreeRangeTotalBalance } from '../../commonStateTypes/coaBal
3
3
  import { defaultCustomerCurrency } from '../../commonStateTypes/currencyHelper';
4
4
  import { reduceFetchStateParallelTimeframes } from '../../commonStateTypes/reduceFetchState';
5
5
  import { getSectionClassesViewReport } from '../../entity/sectionClassesViewV2/sectionClassesViewSelector';
6
+ import { HORIZONTAL_CLASS_TOTAL_BALANCE_ID, } from './profitAndLossClassesByClassHorizontalSelectorTypes';
6
7
  import { enrichProfitAndLossByClassHorizontalReport } from './profitAndLossHorizontalEnrichment';
8
+ /** Standard class ID returned by the accounting platform for transactions without an assigned class. */
9
+ export const NOT_SPECIFIED_CLASS_ID = 'not_specified';
7
10
  export const profitAndLossHorizontalIdsInOrder = [
8
11
  'income',
9
12
  'cogs',
@@ -118,7 +121,19 @@ function buildClassColumns(classHierarchy, classesToFilterOut) {
118
121
  nestedClassId: c.classId,
119
122
  qboId: c.qboId,
120
123
  }))
121
- .sort((a, b) => a.className.localeCompare(b.className, [], { sensitivity: 'base' }));
124
+ .sort((a, b) => {
125
+ const aIsNotSpecified = a.classId === NOT_SPECIFIED_CLASS_ID;
126
+ const bIsNotSpecified = b.classId === NOT_SPECIFIED_CLASS_ID;
127
+ if (aIsNotSpecified && !bIsNotSpecified) {
128
+ return 1;
129
+ }
130
+ if (!aIsNotSpecified && bIsNotSpecified) {
131
+ return -1;
132
+ }
133
+ return a.className.localeCompare(b.className, [], {
134
+ sensitivity: 'base',
135
+ });
136
+ });
122
137
  }
123
138
  /**
124
139
  * Pivot a section from class→account→balances to account→class→balance (single period).
@@ -303,6 +318,7 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod, currency)
303
318
  startDate,
304
319
  type: 'default',
305
320
  label: col.className,
321
+ id: col.classId,
306
322
  }));
307
323
  // Add a "Total" column
308
324
  balances.push({
@@ -312,6 +328,7 @@ function buildHeaderBalances(classColumns, timeframe, selectedPeriod, currency)
312
328
  startDate,
313
329
  type: 'default',
314
330
  label: 'Total',
331
+ id: HORIZONTAL_CLASS_TOTAL_BALANCE_ID,
315
332
  });
316
333
  return balances;
317
334
  }
@@ -72,19 +72,22 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
72
72
  return getEmptyHorizontalSectionBalancesSlice(report.firstMonthOfFY, timeframe);
73
73
  }
74
74
  const { startDate, endDate } = report.selectedPeriod;
75
- const balances = report.classColumns.map((col, columnIndex) => ({
76
- balance: {
77
- amount: classAmounts[columnIndex] ?? 0,
78
- currencyCode,
79
- currencySymbol,
80
- },
81
- balanceTimeFrame: timeframe,
82
- startDate,
83
- endDate,
84
- type: 'default',
85
- id: col.classId,
86
- label: col.className,
87
- }));
75
+ const balances = report.classColumns.map((col, columnIndex) => {
76
+ const amount = classAmounts[columnIndex] ?? 0;
77
+ return {
78
+ balance: {
79
+ amount,
80
+ currencyCode,
81
+ currencySymbol,
82
+ },
83
+ balanceTimeFrame: timeframe,
84
+ startDate,
85
+ endDate,
86
+ type: amount === 0 ? 'default_with_null_balance' : 'default',
87
+ id: col.classId,
88
+ label: col.className,
89
+ };
90
+ });
88
91
  balances.push({
89
92
  balance: {
90
93
  amount: totalAmount,
@@ -94,7 +97,7 @@ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmou
94
97
  balanceTimeFrame: timeframe,
95
98
  startDate,
96
99
  endDate,
97
- type: 'default',
100
+ type: totalAmount === 0 ? 'default_with_null_balance' : 'default',
98
101
  id: HORIZONTAL_CLASS_TOTAL_BALANCE_ID,
99
102
  label: 'Total',
100
103
  });
@@ -0,0 +1,26 @@
1
+ import { date } from '../../../zeniDayJS';
2
+ export const mapPayloadToAutoTransferRule = (payload) => ({
3
+ amount: payload.amount,
4
+ autoTransferRuleId: payload.auto_transfer_rule_id,
5
+ createTime: payload.create_time != null ? date(payload.create_time) : undefined,
6
+ currencyCode: payload.currency_code,
7
+ currencySymbol: payload.currency_symbol ?? '$',
8
+ destinationBankAccountId: payload.destination_bank_account_id,
9
+ destinationBankAccountMetadata: payload.destination_bank_account_metadata?.map((m) => ({
10
+ accountId: m.account_id,
11
+ accountType: m.account_type,
12
+ percentage: m.percentage,
13
+ })) ?? undefined,
14
+ destinationBankAccountType: payload.destination_bank_account_type ?? undefined,
15
+ frequency: payload.frequency,
16
+ isActive: payload.is_active,
17
+ isDeleted: payload.is_deleted,
18
+ lastRunTime: payload.last_run_time,
19
+ nextTransferDate: payload.next_transfer_date != null
20
+ ? date(payload.next_transfer_date)
21
+ : undefined,
22
+ ruleType: payload.rule_type,
23
+ sourceBankAccountId: payload.source_bank_account_id,
24
+ sourceBankAccountType: payload.source_bank_account_type,
25
+ updateTime: payload.update_time != null ? date(payload.update_time) : undefined,
26
+ });