@zeniai/client-epic-state 5.0.1 → 5.0.2-betaRD2

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 (185) hide show
  1. package/lib/commonPayloadTypes/subAccountView/reportBySubAccountPayload.d.ts +2 -0
  2. package/lib/commonStateTypes/coaBalance/coaBalancesFilterProjectView.d.ts +13 -0
  3. package/lib/commonStateTypes/coaBalance/coaBalancesFilterProjectView.js +9 -0
  4. package/lib/commonStateTypes/common.d.ts +1 -1
  5. package/lib/commonStateTypes/projectView/projectViewParentID.d.ts +5 -0
  6. package/lib/commonStateTypes/projectView/projectViewParentID.js +2 -0
  7. package/lib/commonStateTypes/viewAndReport/reportIDHelper.d.ts +1 -0
  8. package/lib/commonStateTypes/viewAndReport/reportIDHelper.js +3 -1
  9. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
  10. package/lib/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  11. package/lib/entity/account/accountReducer.js +6 -3
  12. package/lib/entity/account/accountSelector.d.ts +7 -0
  13. package/lib/entity/account/accountSelector.js +4 -2
  14. package/lib/entity/account/accountState.d.ts +3 -1
  15. package/lib/entity/account/accountState.js +4 -1
  16. package/lib/entity/account/pickAndMergeForecastAccountReport.d.ts +1 -0
  17. package/lib/entity/account/subAccountSelector.d.ts +2 -0
  18. package/lib/entity/account/subAccountSelector.js +2 -0
  19. package/lib/entity/accountGroup/accountGroupSelector.d.ts +22 -0
  20. package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
  21. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerPayload.d.ts +44 -0
  22. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +55 -0
  23. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerReducer.d.ts +10 -0
  24. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +51 -0
  25. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerSelector.d.ts +48 -0
  26. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerSelector.js +66 -0
  27. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerState.d.ts +52 -0
  28. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerState.js +37 -0
  29. package/lib/entity/billPay/billTransaction/billTransactionState.d.ts +2 -2
  30. package/lib/entity/chargeCard/chargeCard.d.ts +1 -1
  31. package/lib/entity/class/classReducer.d.ts +4 -4
  32. package/lib/entity/class/classState.d.ts +1 -1
  33. package/lib/entity/depositAccountTransaction/depositAccountTransaction.d.ts +1 -1
  34. package/lib/entity/entityApprovalStatus/entityApprovalStatusState.d.ts +2 -2
  35. package/lib/entity/forecast/forecastState.d.ts +1 -1
  36. package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
  37. package/lib/entity/project/projectPayload.d.ts +13 -0
  38. package/lib/entity/project/projectPayload.js +30 -0
  39. package/lib/entity/project/projectReducer.d.ts +10 -0
  40. package/lib/entity/project/projectReducer.js +31 -0
  41. package/lib/entity/project/projectSelector.d.ts +5 -0
  42. package/lib/entity/project/projectSelector.js +12 -0
  43. package/lib/entity/project/projectState.d.ts +13 -0
  44. package/lib/entity/project/projectState.js +2 -0
  45. package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
  46. package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
  47. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
  48. package/lib/entity/sectionProjectView/sectionProjectView.d.ts +11 -0
  49. package/lib/entity/sectionProjectView/sectionProjectView.js +6 -0
  50. package/lib/entity/sectionProjectView/sectionProjectViewEpic.d.ts +6 -0
  51. package/lib/entity/sectionProjectView/sectionProjectViewEpic.js +56 -0
  52. package/lib/entity/sectionProjectView/sectionProjectViewHelper.d.ts +10 -0
  53. package/lib/entity/sectionProjectView/sectionProjectViewHelper.js +14 -0
  54. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +15 -0
  55. package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +56 -0
  56. package/lib/entity/sectionProjectView/sectionProjectViewSelector.d.ts +11 -0
  57. package/lib/entity/sectionProjectView/sectionProjectViewSelector.js +94 -0
  58. package/lib/entity/sectionProjectView/sectionProjectViewSelectorTypes.d.ts +16 -0
  59. package/lib/entity/sectionProjectView/sectionProjectViewSelectorTypes.js +2 -0
  60. package/lib/entity/sectionProjectView/sectionProjectViewState.d.ts +4 -0
  61. package/lib/entity/sectionProjectView/sectionProjectViewState.js +2 -0
  62. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  63. package/lib/entity/tenant/clearAllEpic.d.ts +7 -2
  64. package/lib/entity/tenant/clearAllEpic.js +10 -0
  65. package/lib/entity/tenant/tenantPayload.d.ts +1 -0
  66. package/lib/entity/tenant/tenantReducer.js +1 -0
  67. package/lib/entity/tenant/tenantSelector.d.ts +1 -0
  68. package/lib/entity/tenant/tenantSelector.js +9 -1
  69. package/lib/entity/tenant/tenantState.d.ts +1 -0
  70. package/lib/entity/transaction/payloadTypes/transactionPayload.js +0 -21
  71. package/lib/entity/userRole/userRoleType.d.ts +2 -2
  72. package/lib/epic.d.ts +8 -1
  73. package/lib/epic.js +8 -1
  74. package/lib/esm/commonStateTypes/coaBalance/coaBalancesFilterProjectView.js +5 -0
  75. package/lib/esm/commonStateTypes/projectView/projectViewParentID.js +1 -0
  76. package/lib/esm/commonStateTypes/viewAndReport/reportIDHelper.js +1 -0
  77. package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  78. package/lib/esm/entity/account/accountReducer.js +6 -3
  79. package/lib/esm/entity/account/accountSelector.js +4 -2
  80. package/lib/esm/entity/account/accountState.js +4 -1
  81. package/lib/esm/entity/account/subAccountSelector.js +2 -0
  82. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +49 -0
  83. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +47 -0
  84. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerSelector.js +62 -0
  85. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerState.js +31 -0
  86. package/lib/esm/entity/project/projectPayload.js +26 -0
  87. package/lib/esm/entity/project/projectReducer.js +27 -0
  88. package/lib/esm/entity/project/projectSelector.js +8 -0
  89. package/lib/esm/entity/project/projectState.js +1 -0
  90. package/lib/esm/entity/sectionProjectView/sectionProjectView.js +3 -0
  91. package/lib/esm/entity/sectionProjectView/sectionProjectViewEpic.js +52 -0
  92. package/lib/esm/entity/sectionProjectView/sectionProjectViewHelper.js +10 -0
  93. package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +52 -0
  94. package/lib/esm/entity/sectionProjectView/sectionProjectViewSelector.js +87 -0
  95. package/lib/esm/entity/sectionProjectView/sectionProjectViewSelectorTypes.js +1 -0
  96. package/lib/esm/entity/sectionProjectView/sectionProjectViewState.js +1 -0
  97. package/lib/esm/entity/tenant/clearAllEpic.js +10 -0
  98. package/lib/esm/entity/tenant/tenantReducer.js +1 -0
  99. package/lib/esm/entity/tenant/tenantSelector.js +7 -0
  100. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +0 -21
  101. package/lib/esm/epic.js +8 -1
  102. package/lib/esm/index.js +14 -4
  103. package/lib/esm/reducer.js +15 -0
  104. package/lib/esm/view/aiAccountantView/aiAccountantViewPayload.js +2 -0
  105. package/lib/esm/view/aiAccountantView/aiAccountantViewReducer.js +149 -0
  106. package/lib/esm/view/aiAccountantView/aiAccountantViewSelector.js +72 -0
  107. package/lib/esm/view/aiAccountantView/aiAccountantViewState.js +11 -0
  108. package/lib/esm/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.js +46 -0
  109. package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +27 -0
  110. package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +47 -0
  111. package/lib/esm/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +52 -0
  112. package/lib/esm/view/financeStatement/financeStatementSelector.js +12 -1
  113. package/lib/esm/view/profitAndLossProjectView/profitAndLossForTimeframeProjectViewEpic.js +47 -0
  114. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewEpic.js +30 -0
  115. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewPayload.js +1 -0
  116. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewReducer.js +113 -0
  117. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewSelector.js +65 -0
  118. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewSelectorTypes.js +1 -0
  119. package/lib/esm/view/profitAndLossProjectView/profitAndLossProjectViewState.js +1 -0
  120. package/lib/esm/view/reportsResync/reportsClassViewRefetchingEpic.js +4 -0
  121. package/lib/index.d.ts +20 -4
  122. package/lib/index.js +73 -34
  123. package/lib/reducer.d.ts +15 -0
  124. package/lib/reducer.js +15 -0
  125. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  126. package/lib/view/aiAccountantView/aiAccountantViewPayload.d.ts +31 -0
  127. package/lib/view/aiAccountantView/aiAccountantViewPayload.js +8 -0
  128. package/lib/view/aiAccountantView/aiAccountantViewReducer.d.ts +29 -0
  129. package/lib/view/aiAccountantView/aiAccountantViewReducer.js +153 -0
  130. package/lib/view/aiAccountantView/aiAccountantViewSelector.d.ts +14 -0
  131. package/lib/view/aiAccountantView/aiAccountantViewSelector.js +78 -0
  132. package/lib/view/aiAccountantView/aiAccountantViewState.d.ts +26 -0
  133. package/lib/view/aiAccountantView/aiAccountantViewState.js +13 -0
  134. package/lib/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.d.ts +33 -0
  135. package/lib/view/aiAccountantView/epics/cancelAiAccountantOnboardingEpic.js +50 -0
  136. package/lib/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.d.ts +23 -0
  137. package/lib/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +31 -0
  138. package/lib/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.d.ts +33 -0
  139. package/lib/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +51 -0
  140. package/lib/view/aiAccountantView/epics/triggerAiAccountantJobEpic.d.ts +28 -0
  141. package/lib/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +56 -0
  142. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  143. package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
  144. package/lib/view/cardBalance/cardBalanceSelector.d.ts +2 -1
  145. package/lib/view/cashBalance/cashBalanceSelector.d.ts +2 -1
  146. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
  147. package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
  148. package/lib/view/companyView/types/cockpitTypes.d.ts +6 -5
  149. package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
  150. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  151. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +1 -1
  152. package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
  153. package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
  154. package/lib/view/financeStatement/financeStatementSelector.js +12 -1
  155. package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
  156. package/lib/view/onboardingView/cockpitView/types/onboardingCockpitViewTypes.d.ts +1 -1
  157. package/lib/view/profitAndLossProjectView/profitAndLossForTimeframeProjectViewEpic.d.ts +9 -0
  158. package/lib/view/profitAndLossProjectView/profitAndLossForTimeframeProjectViewEpic.js +51 -0
  159. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewEpic.d.ts +6 -0
  160. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewEpic.js +34 -0
  161. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewPayload.d.ts +33 -0
  162. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewPayload.js +2 -0
  163. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewReducer.d.ts +33 -0
  164. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewReducer.js +117 -0
  165. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewSelector.d.ts +9 -0
  166. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewSelector.js +69 -0
  167. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewSelectorTypes.d.ts +19 -0
  168. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewSelectorTypes.js +2 -0
  169. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewState.d.ts +22 -0
  170. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewState.js +2 -0
  171. package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
  172. package/lib/view/reportsResync/reportsClassViewRefetchingEpic.d.ts +2 -1
  173. package/lib/view/reportsResync/reportsClassViewRefetchingEpic.js +4 -0
  174. package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
  175. package/lib/view/reviewCompanyView/reviewCompanyViewState.d.ts +1 -1
  176. package/lib/view/spendManagement/billPay/billList/billListReducer.d.ts +1 -1
  177. package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
  178. package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetail.d.ts +1 -1
  179. package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.d.ts +4 -4
  180. package/lib/view/spendManagement/reimbursement/remiListView/remiListReducer.d.ts +1 -1
  181. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +3 -3
  182. package/lib/view/subscriptionView/types/subscriptionTypes.d.ts +1 -1
  183. package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
  184. package/lib/view/topEx/topExSelector.d.ts +1 -1
  185. package/package.json +1 -1
@@ -14,6 +14,7 @@ import chargeCard, { initialState as initialChargeCardState, } from './entity/ch
14
14
  import chargeCardRepayment, { initialState as initialChargeCardRepaymentState, } from './entity/chargeCardRepayment/chargeCardRepaymentReducer';
15
15
  import chargeCardTransaction, { initialState as initialChargeCardTransactionState, } from './entity/chargeCardTransaction/chargeCardTransactionReducer';
16
16
  import classes, { initialState as initialClassState, } from './entity/class/classReducer';
17
+ import project, { initialState as initialProjectState, } from './entity/project/projectReducer';
17
18
  import company, { initialState as initialCompanyState, } from './entity/company/companyReducer';
18
19
  import companyHealthMetric, { initialState as initialCompanyHealthMetricState, } from './entity/companyHealthMetric/companyHealthMetricReducer';
19
20
  import connectedAccount, { initialState as initialConnectedAccountState, } from './entity/connectedAccount/connectedAccountReducer';
@@ -41,6 +42,7 @@ import accountingSummary, { initialState as initialAccountingSummaryState, } fro
41
42
  import reimbursement, { initialState as initialReimbursementState, } from './entity/reimbursement/reimbursementReducer';
42
43
  import sectionAccountsView, { initialState as initialSectionAccountsViewState, } from './entity/sectionAccountsView/sectionAccountsViewReducer';
43
44
  import sectionClassesViewV2, { initialState as initialSectionClassesViewStateV2, } from './entity/sectionClassesViewV2/sectionClassesViewReducer';
45
+ import sectionProjectView, { initialState as initialSectionProjectViewState, } from './entity/sectionProjectView/sectionProjectViewReducer';
44
46
  import snackbar, { initialSnackbarState, } from './entity/snackbar/snackbarReducer';
45
47
  import subscription, { initialState as initialSubscriptionState, } from './entity/subscription/subscription/subscriptionReducer';
46
48
  import subscriptionAddOn, { initialState as initialSubscriptionAddOnState, } from './entity/subscription/subscriptionAddOn/subscriptionAddOnReducer';
@@ -67,6 +69,8 @@ import accountMapping, { initialState as initialAccountMappingState, } from './v
67
69
  import addressView, { initialState as initialAddressViewState, } from './view/addressView/addressViewReducer';
68
70
  import aggregatedReport, { initialState as initialAggregatedReportViewState, } from './view/aiAgentPerformance/aggregatedReportViewReducer';
69
71
  import aiCfoView, { initialAiCfoViewState, } from './view/aiCfoView/aiCfoViewReducer';
72
+ import aiAccountantCustomer, { initialAiAccountantCustomerState, } from './entity/aiAccountantCustomer/aiAccountantCustomerReducer';
73
+ import aiAccountantView, { initialAiAccountantViewState, } from './view/aiAccountantView/aiAccountantViewReducer';
70
74
  import apAgingDetail, { initialState as initialApAgingDetailState, } from './view/apAgingView/apAgingDetail/apAgingDetailReducer';
71
75
  import apAging, { initialState as initialApAgingState, } from './view/apAgingView/apAgingReport/apAgingReducer';
72
76
  import arAgingDetail, { initialState as initialArAgingDetailState, } from './view/arAgingView/arAgingDetail/arAgingDetailReducer';
@@ -122,6 +126,7 @@ import ownerList, { initialState as initialOwnerListState, } from './view/ownerL
122
126
  import people, { initialState as initialPeopleState, } from './view/people/peopleReducer';
123
127
  import profitAndLoss, { initialState as initialProfitAndLossState, } from './view/profitAndLoss/profitAndLossReducer';
124
128
  import profitAndLossClassesView, { initialState as initialProfitAndLossClassesViewState, } from './view/profitAndLossClassesView/profitAndLossClassesViewReducer';
129
+ import profitAndLossProjectView, { initialState as initialProfitAndLossProjectViewState, } from './view/profitAndLossProjectView/profitAndLossProjectViewReducer';
125
130
  import recommendation, { initialState as initialEntityRecommendationState, } from './view/recommendation/recommendationReducer';
126
131
  import referralView, { initialState as initialReferralViewState, } from './view/referralView/referralReducer';
127
132
  import reimbursementCard, { initialState as initialReimbursementCardState, } from './view/reimbursementCard/reimbursementCardReducer';
@@ -220,6 +225,7 @@ const initialEntitiesState = {
220
225
  accountReconState: initialAccountReconState,
221
226
  accountState: initialAccountState,
222
227
  addressState: initialAddressState,
228
+ aiAccountantCustomerState: initialAiAccountantCustomerState,
223
229
  aiCfoState: initialAiCfoState,
224
230
  approvalRuleState: initialApprovalRuleState,
225
231
  bankAccountState: initialBankAccountState,
@@ -229,6 +235,7 @@ const initialEntitiesState = {
229
235
  chargeCardRepaymentState: initialChargeCardRepaymentState,
230
236
  chargeCardTransactionState: initialChargeCardTransactionState,
231
237
  classState: initialClassState,
238
+ projectState: initialProjectState,
232
239
  companyHealthMetricState: initialCompanyHealthMetricState,
233
240
  companyState: initialCompanyState,
234
241
  connectedAccountState: initialConnectedAccountState,
@@ -257,6 +264,7 @@ const initialEntitiesState = {
257
264
  reimbursementState: initialReimbursementState,
258
265
  sectionAccountsViewState: initialSectionAccountsViewState,
259
266
  sectionClassesViewStateV2: initialSectionClassesViewStateV2,
267
+ sectionProjectViewState: initialSectionProjectViewState,
260
268
  snackbarState: initialSnackbarState,
261
269
  subscriptionAddOnState: initialSubscriptionAddOnState,
262
270
  subscriptionCouponState: initialSubscriptionCouponState,
@@ -286,6 +294,7 @@ const initialViewsState = {
286
294
  accountMappingState: initialAccountMappingState,
287
295
  addressViewState: initialAddressViewState,
288
296
  aggregatedReportViewState: initialAggregatedReportViewState,
297
+ aiAccountantViewState: initialAiAccountantViewState,
289
298
  aiCfoViewState: initialAiCfoViewState,
290
299
  apAgingDetailState: initialApAgingDetailState,
291
300
  apAgingState: initialApAgingState,
@@ -371,6 +380,7 @@ const initialViewsState = {
371
380
  plaidAccountViewState: initialPlaidAccountViewState,
372
381
  previousBillsState: initialPreviousBillsState,
373
382
  profitAndLossClassesViewState: initialProfitAndLossClassesViewState,
383
+ profitAndLossProjectViewState: initialProfitAndLossProjectViewState,
374
384
  profitAndLossState: initialProfitAndLossState,
375
385
  realTimeApprovalState: initialRealTimeApprovalState,
376
386
  referralViewState: initialReferralViewState,
@@ -444,6 +454,7 @@ const entityReducers = {
444
454
  accountingSummaryState: accountingSummary,
445
455
  accountState: account,
446
456
  addressState: address,
457
+ aiAccountantCustomerState: aiAccountantCustomer,
447
458
  aiCfoState: aiCfo,
448
459
  approvalRuleState: approvalRule,
449
460
  bankAccountState: bankAccount,
@@ -454,6 +465,7 @@ const entityReducers = {
454
465
  chargeCardRepaymentState: chargeCardRepayment,
455
466
  chargeCardTransactionState: chargeCardTransaction,
456
467
  classState: classes,
468
+ projectState: project,
457
469
  companyHealthMetricState: companyHealthMetric,
458
470
  companyState: company,
459
471
  connectedAccountState: connectedAccount,
@@ -482,6 +494,7 @@ const entityReducers = {
482
494
  reimbursementState: reimbursement,
483
495
  sectionAccountsViewState: sectionAccountsView,
484
496
  sectionClassesViewStateV2: sectionClassesViewV2,
497
+ sectionProjectViewState: sectionProjectView,
485
498
  snackbarState: snackbar,
486
499
  subscriptionAddOnState: subscriptionAddOn,
487
500
  subscriptionCouponState: subscriptionCoupon,
@@ -511,6 +524,7 @@ const viewReducers = {
511
524
  accountMappingState: accountMapping,
512
525
  addressViewState: addressView,
513
526
  aggregatedReportViewState: aggregatedReport,
527
+ aiAccountantViewState: aiAccountantView,
514
528
  aiCfoViewState: aiCfoView,
515
529
  apAgingDetailState: apAgingDetail,
516
530
  apAgingState: apAging,
@@ -596,6 +610,7 @@ const viewReducers = {
596
610
  plaidAccountViewState: plaidAccountView,
597
611
  previousBillsState: previousBills,
598
612
  profitAndLossClassesViewState: profitAndLossClassesView,
613
+ profitAndLossProjectViewState: profitAndLossProjectView,
599
614
  profitAndLossState: profitAndLoss,
600
615
  realTimeApprovalState: realTimeApproval,
601
616
  referralViewState: referralView,
@@ -0,0 +1,2 @@
1
+ // Re-export entity payload types and mapping functions.
2
+ export { toAiAccountantCustomer, toAiAccountantEnrollment, toAiAccountantJob, } from '../../entity/aiAccountantCustomer/aiAccountantCustomerPayload';
@@ -0,0 +1,149 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialAiAccountantViewState = {
3
+ customersByTenantId: {},
4
+ customersFetchStatus: { fetchState: 'Not-Started' },
5
+ selectedTenantIdsForJobTrigger: [],
6
+ triggerJobStatus: { fetchState: 'Not-Started' },
7
+ uiState: {
8
+ filterText: '',
9
+ filters: {},
10
+ selectedCustomerTenantId: '',
11
+ sortKey: 'companyName',
12
+ sortOrder: 'ascending',
13
+ },
14
+ };
15
+ const aiAccountantView = createSlice({
16
+ name: 'aiAccountantView',
17
+ initialState: initialAiAccountantViewState,
18
+ reducers: {
19
+ // ── Customers ──
20
+ fetchAiAccountantCustomers(draft) {
21
+ draft.customersFetchStatus = { fetchState: 'In-Progress' };
22
+ },
23
+ updateAiAccountantCustomers(draft, action) {
24
+ draft.customersByTenantId = toCustomersByTenantId(action.payload, draft.customersByTenantId);
25
+ draft.customersFetchStatus = { fetchState: 'Completed' };
26
+ },
27
+ updateAiAccountantCustomersFailure(draft, action) {
28
+ draft.customersFetchStatus = {
29
+ fetchState: 'Error',
30
+ error: action.payload,
31
+ };
32
+ },
33
+ // ── Jobs ──
34
+ fetchAiAccountantJobs: {
35
+ reducer(draft, action) {
36
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
37
+ if (customerView != null) {
38
+ customerView.jobsFetchStatus = { fetchState: 'In-Progress' };
39
+ }
40
+ },
41
+ prepare(tenantId, fetchNextPage) {
42
+ return { payload: { tenantId, fetchNextPage: fetchNextPage ?? false } };
43
+ },
44
+ },
45
+ updateAiAccountantJobs: {
46
+ reducer(draft, action) {
47
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
48
+ if (customerView != null) {
49
+ customerView.jobsFetchStatus = { fetchState: 'Completed' };
50
+ customerView.jobsPageToken = action.payload.nextPageToken;
51
+ }
52
+ },
53
+ prepare(tenantId, nextPageToken) {
54
+ return { payload: { tenantId, nextPageToken: nextPageToken ?? null } };
55
+ },
56
+ },
57
+ updateAiAccountantJobsFailure(draft, action) {
58
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
59
+ if (customerView != null) {
60
+ customerView.jobsFetchStatus = {
61
+ fetchState: 'Error',
62
+ error: action.payload.error,
63
+ };
64
+ }
65
+ },
66
+ setSelectedTenantIdsForJobTrigger(draft, action) {
67
+ draft.selectedTenantIdsForJobTrigger = action.payload;
68
+ },
69
+ // ── Trigger Job ──
70
+ triggerAiAccountantJob: {
71
+ reducer(draft,
72
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
73
+ _action) {
74
+ draft.triggerJobStatus = { fetchState: 'In-Progress' };
75
+ },
76
+ prepare(operationType, startDate, endDate) {
77
+ return { payload: { operationType, startDate, endDate } };
78
+ },
79
+ },
80
+ triggerAiAccountantJobSuccess(draft) {
81
+ draft.triggerJobStatus = { fetchState: 'Completed' };
82
+ },
83
+ triggerAiAccountantJobFailure(draft, action) {
84
+ draft.triggerJobStatus = { fetchState: 'Error', error: action.payload };
85
+ },
86
+ // ── Cancel Onboarding ──
87
+ cancelAiAccountantOnboarding: {
88
+ reducer(draft, action) {
89
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
90
+ if (customerView != null) {
91
+ customerView.cancelOnboardingStatus = { fetchState: 'In-Progress' };
92
+ }
93
+ },
94
+ prepare(companyId, tenantId) {
95
+ return { payload: { companyId, tenantId } };
96
+ },
97
+ },
98
+ cancelAiAccountantOnboardingSuccess: {
99
+ reducer(draft, action) {
100
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
101
+ if (customerView != null) {
102
+ customerView.cancelOnboardingStatus = { fetchState: 'Completed' };
103
+ }
104
+ },
105
+ prepare(tenantId) {
106
+ return { payload: { tenantId } };
107
+ },
108
+ },
109
+ cancelAiAccountantOnboardingFailure: {
110
+ reducer(draft, action) {
111
+ const customerView = draft.customersByTenantId[action.payload.tenantId];
112
+ if (customerView != null) {
113
+ customerView.cancelOnboardingStatus = {
114
+ fetchState: 'Error',
115
+ error: action.payload.error,
116
+ };
117
+ }
118
+ },
119
+ prepare(tenantId, error) {
120
+ return { payload: { tenantId, error } };
121
+ },
122
+ },
123
+ // ── UI State ──
124
+ updateAiAccountantUIState(draft, action) {
125
+ Object.assign(draft.uiState, action.payload);
126
+ },
127
+ // ── Clear ──
128
+ clearAiAccountantView() {
129
+ return initialAiAccountantViewState;
130
+ },
131
+ },
132
+ });
133
+ export const { cancelAiAccountantOnboarding, cancelAiAccountantOnboardingFailure, cancelAiAccountantOnboardingSuccess, clearAiAccountantView, fetchAiAccountantCustomers, fetchAiAccountantJobs, setSelectedTenantIdsForJobTrigger, triggerAiAccountantJob, triggerAiAccountantJobFailure, triggerAiAccountantJobSuccess, updateAiAccountantCustomers, updateAiAccountantCustomersFailure, updateAiAccountantJobs, updateAiAccountantJobsFailure, updateAiAccountantUIState, } = aiAccountantView.actions;
134
+ export default aiAccountantView.reducer;
135
+ // ── Helpers ──
136
+ const toCustomersByTenantId = (customers, existing) => {
137
+ const result = {};
138
+ for (const payload of customers) {
139
+ const tenantId = payload.tenant_id;
140
+ const existingState = existing[tenantId];
141
+ result[tenantId] = existingState ?? {
142
+ cancelOnboardingStatus: { fetchState: 'Not-Started' },
143
+ jobsFetchStatus: { fetchState: 'Not-Started' },
144
+ jobsPageToken: null,
145
+ tenantId,
146
+ };
147
+ }
148
+ return result;
149
+ };
@@ -0,0 +1,72 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+ import orderBy from 'lodash/orderBy';
3
+ import { getAiAccountantCustomers, } from '../../entity/aiAccountantCustomer/aiAccountantCustomerSelector';
4
+ export const getAiAccountantCockpitView = createSelector((state) => state.aiAccountantViewState, (state) => state.aiAccountantCustomerState, (state) => state.userState, (viewState, customerEntityState, userState) => {
5
+ const { customersByTenantId, customersFetchStatus, selectedTenantIdsForJobTrigger, triggerJobStatus, uiState, } = viewState;
6
+ const allCustomers = getAiAccountantCustomers(customerEntityState, userState);
7
+ let filteredCustomers = allCustomers;
8
+ // Text filter
9
+ const trimmedFilterText = uiState.filterText.trim();
10
+ if (trimmedFilterText.length > 0) {
11
+ const query = trimmedFilterText.toLowerCase();
12
+ filteredCustomers = filteredCustomers.filter((customer) => customer.companyName.toLowerCase().includes(query) ||
13
+ customer.tenantId.toLowerCase().includes(query));
14
+ }
15
+ // Cockpit filters (e.g. enrollmentStatus)
16
+ const enrollmentStatusFilter = uiState.filters.categories?.find((category) => category.field === 'enrollmentStatus');
17
+ if (enrollmentStatusFilter != null &&
18
+ enrollmentStatusFilter.values.length > 0) {
19
+ const selectedStatuses = enrollmentStatusFilter.values.map(String);
20
+ const isEqual = enrollmentStatusFilter.matchingOperator === 'equal';
21
+ filteredCustomers = filteredCustomers.filter((customer) => {
22
+ const status = customer.enrollment?.status ?? 'unknown';
23
+ const matches = selectedStatuses.includes(status);
24
+ return isEqual ? matches : !matches;
25
+ });
26
+ }
27
+ // Sorting
28
+ const sortedCustomers = getSortedCustomers(filteredCustomers, uiState.sortKey, uiState.sortOrder);
29
+ const selectedCustomersForJobTrigger = allCustomers.filter((customer) => selectedTenantIdsForJobTrigger.includes(customer.tenantId));
30
+ return {
31
+ averageAccuracy: calcOverallAverageAccuracy(allCustomers),
32
+ fetchState: customersFetchStatus.fetchState,
33
+ error: customersFetchStatus.error,
34
+ customers: sortedCustomers,
35
+ customerViewStateByTenantId: customersByTenantId,
36
+ selectedCustomersForJobTrigger,
37
+ triggerJobStatus,
38
+ uiState,
39
+ };
40
+ });
41
+ // ── Helpers ──
42
+ const getSortedCustomers = (customers, sortKey, sortOrder) => {
43
+ const direction = sortOrder === 'ascending' ? 'asc' : 'desc';
44
+ return orderBy(customers, (customer) => {
45
+ switch (sortKey) {
46
+ case 'companyName':
47
+ return customer.companyName.toLowerCase();
48
+ case 'status':
49
+ return (customer.enrollment?.status ?? 'unknown').toLowerCase();
50
+ case 'bookcloseDate':
51
+ return customer.bookcloseDate?.valueOf() ?? 0;
52
+ case 'latestTraining':
53
+ return customer.enrollment?.latestTraining?.valueOf() ?? 0;
54
+ case 'latestSync':
55
+ return customer.enrollment?.latestTransactionSync?.valueOf() ?? 0;
56
+ case 'accuracy':
57
+ return customer.averageAccuracy;
58
+ default:
59
+ return customer.companyName.toLowerCase();
60
+ }
61
+ }, direction);
62
+ };
63
+ const calcOverallAverageAccuracy = (customers) => {
64
+ const customerAccuracies = customers
65
+ .map((customer) => customer.averageAccuracy)
66
+ .filter((accuracy) => accuracy > 0);
67
+ if (customerAccuracies.length === 0) {
68
+ return 0;
69
+ }
70
+ return (customerAccuracies.reduce((sum, accuracy) => sum + accuracy, 0) /
71
+ customerAccuracies.length);
72
+ };
@@ -0,0 +1,11 @@
1
+ import { stringToUnion } from '../../commonStateTypes/stringToUnion';
2
+ const ALL_AI_ACCOUNTANT_SORT_KEYS = [
3
+ 'companyName',
4
+ 'status',
5
+ 'bookcloseDate',
6
+ 'latestTraining',
7
+ 'latestSync',
8
+ 'accuracy',
9
+ ];
10
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
+ const toAiAccountantSortKeyType = (v) => stringToUnion(v, ALL_AI_ACCOUNTANT_SORT_KEYS);
@@ -0,0 +1,46 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
+ import { cancelAiAccountantOnboarding, cancelAiAccountantOnboardingFailure, cancelAiAccountantOnboardingSuccess, fetchAiAccountantCustomers, } from '../aiAccountantViewReducer';
6
+ export const cancelAiAccountantOnboardingEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(cancelAiAccountantOnboarding.match), mergeMap((action) => {
7
+ const { tenantId, companyId } = action.payload;
8
+ const base = `${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/cockpit-panels`;
9
+ const url = `${base}/ai-accountant/cancel-onboarding`;
10
+ return zeniAPI
11
+ .postAndGetJSON(url, {
12
+ tenant_id: tenantId,
13
+ company_id: companyId,
14
+ })
15
+ .pipe(mergeMap((response) => {
16
+ if (isSuccessResponse(response)) {
17
+ return from([
18
+ cancelAiAccountantOnboardingSuccess(tenantId),
19
+ fetchAiAccountantCustomers(),
20
+ openSnackbar({
21
+ messageSection: 'common',
22
+ messageText: 'success',
23
+ type: 'success',
24
+ }),
25
+ ]);
26
+ }
27
+ else {
28
+ return from([
29
+ cancelAiAccountantOnboardingFailure(tenantId, response.status),
30
+ openSnackbar({
31
+ messageSection: 'common',
32
+ messageText: 'failed',
33
+ type: 'error',
34
+ }),
35
+ ]);
36
+ }
37
+ }), catchError((error) => from([
38
+ cancelAiAccountantOnboardingFailure(tenantId, createZeniAPIStatus('Unexpected error', 'AI Accountant cancel onboarding failed: ' +
39
+ JSON.stringify(error))),
40
+ openSnackbar({
41
+ messageSection: 'common',
42
+ messageText: 'failed',
43
+ type: 'error',
44
+ }),
45
+ ])));
46
+ }));
@@ -0,0 +1,27 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateAiAccountantCustomers as updateAiAccountantCustomerEntities } from '../../../entity/aiAccountantCustomer/aiAccountantCustomerReducer';
4
+ import { updateAllUsers } from '../../../entity/user/userReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
6
+ import { fetchAiAccountantCustomers, updateAiAccountantCustomers, updateAiAccountantCustomersFailure, } from '../aiAccountantViewReducer';
7
+ export const fetchAiAccountantCustomersEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchAiAccountantCustomers.match), switchMap(() => {
8
+ const base = `${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/cockpit-panels`;
9
+ const url = `${base}/ai-accountant/customers`;
10
+ return zeniAPI
11
+ .getJSON(url)
12
+ .pipe(mergeMap((response) => {
13
+ if (isSuccessResponse(response)) {
14
+ const customers = response.data?.customers ?? [];
15
+ const users = response.data?.users ?? [];
16
+ return from([
17
+ updateAiAccountantCustomerEntities(customers),
18
+ updateAllUsers({ users }),
19
+ updateAiAccountantCustomers(customers),
20
+ ]);
21
+ }
22
+ else {
23
+ return of(updateAiAccountantCustomersFailure(response.status));
24
+ }
25
+ }), catchError((error) => of(updateAiAccountantCustomersFailure(createZeniAPIStatus('Unexpected error', 'AI Accountant customers fetch failed: ' +
26
+ JSON.stringify(error))))));
27
+ }));
@@ -0,0 +1,47 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateAiAccountantJobs as updateAiAccountantJobEntities } from '../../../entity/aiAccountantCustomer/aiAccountantCustomerReducer';
4
+ import { updateAllUsers } from '../../../entity/user/userReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
6
+ import { fetchAiAccountantJobs, updateAiAccountantJobs, updateAiAccountantJobsFailure, } from '../aiAccountantViewReducer';
7
+ export const fetchAiAccountantJobsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchAiAccountantJobs.match), switchMap((action) => {
8
+ const { tenantId, fetchNextPage } = action.payload;
9
+ const rootState = state$.value;
10
+ const customerView = rootState.aiAccountantViewState.customersByTenantId[tenantId];
11
+ const pageToken = fetchNextPage && customerView?.jobsPageToken != null
12
+ ? customerView.jobsPageToken
13
+ : null;
14
+ const params = new URLSearchParams({
15
+ page_size: '50',
16
+ tenant_id: tenantId,
17
+ });
18
+ if (pageToken != null) {
19
+ params.set('page_token', pageToken);
20
+ }
21
+ const base = `${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/cockpit-panels`;
22
+ const url = `${base}/ai-accountant/jobs?${params.toString()}`;
23
+ return zeniAPI
24
+ .getJSON(url)
25
+ .pipe(mergeMap((response) => {
26
+ if (isSuccessResponse(response)) {
27
+ const jobs = response.data?.jobs ?? [];
28
+ const users = response.data?.users ?? [];
29
+ const nextPageToken = response.data?.next_page_token ?? null;
30
+ return from([
31
+ updateAllUsers({ users }),
32
+ updateAiAccountantJobEntities(tenantId, jobs, fetchNextPage),
33
+ updateAiAccountantJobs(tenantId, nextPageToken),
34
+ ]);
35
+ }
36
+ else {
37
+ return of(updateAiAccountantJobsFailure({
38
+ tenantId,
39
+ error: response.status,
40
+ }));
41
+ }
42
+ }), catchError((error) => of(updateAiAccountantJobsFailure({
43
+ tenantId,
44
+ error: createZeniAPIStatus('Unexpected error', 'AI Accountant jobs fetch failed: ' +
45
+ JSON.stringify(error)),
46
+ }))));
47
+ }));
@@ -0,0 +1,52 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
+ import { fetchAiAccountantCustomers, triggerAiAccountantJob, triggerAiAccountantJobFailure, triggerAiAccountantJobSuccess, } from '../aiAccountantViewReducer';
6
+ export const triggerAiAccountantJobEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(triggerAiAccountantJob.match), mergeMap((action) => {
7
+ const { operationType, startDate, endDate } = action.payload;
8
+ const rootState = state$.value;
9
+ const selectedTenantIds = rootState.aiAccountantViewState.selectedTenantIdsForJobTrigger;
10
+ const base = `${zeniAPI.apiEndPoints.tenantMicroServiceBaseUrl}/1.0/cockpit-panels`;
11
+ const url = `${base}/ai-accountant/jobs`;
12
+ const params = operationType === 'offboard'
13
+ ? {}
14
+ : { start_date: startDate, end_date: endDate };
15
+ return zeniAPI
16
+ .postAndGetJSON(url, {
17
+ tenant_ids: selectedTenantIds,
18
+ operation_type: operationType,
19
+ params,
20
+ })
21
+ .pipe(mergeMap((response) => {
22
+ if (isSuccessResponse(response)) {
23
+ return from([
24
+ triggerAiAccountantJobSuccess(),
25
+ fetchAiAccountantCustomers(),
26
+ openSnackbar({
27
+ messageSection: 'common',
28
+ messageText: 'success',
29
+ type: 'success',
30
+ }),
31
+ ]);
32
+ }
33
+ else {
34
+ return from([
35
+ triggerAiAccountantJobFailure(response.status),
36
+ openSnackbar({
37
+ messageSection: 'common',
38
+ messageText: 'failed',
39
+ type: 'error',
40
+ }),
41
+ ]);
42
+ }
43
+ }), catchError((error) => from([
44
+ triggerAiAccountantJobFailure(createZeniAPIStatus('Unexpected error', 'AI Accountant trigger job failed: ' +
45
+ JSON.stringify(error))),
46
+ openSnackbar({
47
+ messageSection: 'common',
48
+ messageText: 'failed',
49
+ type: 'error',
50
+ }),
51
+ ])));
52
+ }));
@@ -9,8 +9,10 @@ import { extractThisPeriod } from '../../commonStateTypes/viewAndReport/thisPeri
9
9
  import { getBalanceSheet } from '../balanceSheet/balanceSheetSelector';
10
10
  import { getCashFlow } from '../cashFlow/cashFlowSelector';
11
11
  import { getProfitAndLossReport, } from '../profitAndLoss/profitAndLossSelector';
12
+ import { newBalancesFilterProjectView } from '../../commonStateTypes/coaBalance/coaBalancesFilterProjectView';
12
13
  import { getProfitAndLossClassesHorizontalView } from '../profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector';
13
14
  import { getProfitAndLossClassesView } from '../profitAndLossClassesView/profitAndLossClassesViewSelector';
15
+ import { getProfitAndLossProjectView } from '../profitAndLossProjectView/profitAndLossProjectViewSelector';
14
16
  function getDateRangeForFinanceReports(profitAndLossState, balanceSheetState, cashFlowState) {
15
17
  const datesSorted = [
16
18
  profitAndLossState.dataAvailable?.startDate,
@@ -35,7 +37,7 @@ function getFirstMonthOfFY(profitAndLossState, balanceSheetState, cashFlowState)
35
37
  cashFlowState.firstMonthOfFY ??
36
38
  1);
37
39
  }
38
- export const getFinanceStatement = createSelector((state) => state.accountState, (state) => state.accountGroupState, (state) => state.classState, (state) => state.sectionClassesViewStateV2, (state) => state.profitAndLossState, (state) => state.profitAndLossClassesViewState, (state) => state.balanceSheetState, (state) => state.cashFlowState, (state) => state.financeStatementState, (state) => state.sectionAccountsViewState, (state) => state.forecastState, (accountState, accountGroupState, classState, sectionsState, profitAndLossState, profitAndLossClassesViewState, balanceSheetState, cashFlowState, financeStatementState, sectionAccountsViewState, forecastState) => {
40
+ export const getFinanceStatement = createSelector((state) => state.accountState, (state) => state.accountGroupState, (state) => state.classState, (state) => state.sectionClassesViewStateV2, (state) => state.profitAndLossState, (state) => state.profitAndLossClassesViewState, (state) => state.projectState, (state) => state.sectionProjectViewState, (state) => state.profitAndLossProjectViewState, (state) => state.balanceSheetState, (state) => state.cashFlowState, (state) => state.financeStatementState, (state) => state.sectionAccountsViewState, (state) => state.forecastState, (accountState, accountGroupState, classState, sectionsState, profitAndLossState, profitAndLossClassesViewState, projectState, sectionProjectViewState, profitAndLossProjectViewState, balanceSheetState, cashFlowState, financeStatementState, sectionAccountsViewState, forecastState) => {
39
41
  // to get min and max dates across three reports
40
42
  let allTimeframeTicks = [];
41
43
  let balancesInTimeframe = [];
@@ -69,6 +71,8 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
69
71
  const profitAndLossReport = getProfitAndLossReport(filter, undefined, accountState, accountGroupState, sectionAccountsViewState, profitAndLossState, forecastState);
70
72
  const classFilter = newBalancesFilterClassesView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, profitAndLossClassesViewState.uiState.classesToFilterOut);
71
73
  const profitAndLossByClassReport = getProfitAndLossClassesView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState);
74
+ const projectFilter = newBalancesFilterProjectView(filter.firstMonthOfFY, filter.timeframe, filter.balancesRange.numberOfPeriods, filter.balancesRange.thisPeriod, filter.balancesRange.orderBy, filter.additionalBalances, profitAndLossProjectViewState.uiState.projectsToFilterOut);
75
+ const profitAndLossByProjectReport = getProfitAndLossProjectView(projectFilter, accountState, projectState, sectionProjectViewState, profitAndLossProjectViewState);
72
76
  const profitAndLossByClassHorizontalReport = getProfitAndLossClassesHorizontalView(classFilter, accountState, classState, sectionsState, profitAndLossClassesViewState, profitAndLossClassesViewState.uiState.classViewLayout === 'horizontal'
73
77
  ? thisPeriod
74
78
  : undefined);
@@ -89,6 +93,12 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
89
93
  error: profitAndLossReport.error,
90
94
  };
91
95
  break;
96
+ case 'profit_and_loss_by_projects':
97
+ selectedReportAndTimeframeFetchState = {
98
+ fetchState: profitAndLossByProjectReport.fetchState,
99
+ error: profitAndLossByProjectReport.error,
100
+ };
101
+ break;
92
102
  case 'balance_sheet':
93
103
  selectedReportAndTimeframeFetchState = {
94
104
  fetchState: balanceSheetReport.fetchState,
@@ -119,6 +129,7 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
119
129
  dataAvailable,
120
130
  profitAndLossReport,
121
131
  profitAndLossByClassReport,
132
+ profitAndLossByProjectReport,
122
133
  profitAndLossByClassHorizontalReport,
123
134
  balanceSheetReport,
124
135
  cashFlowReport,
@@ -0,0 +1,47 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { updateProjects } from '../../entity/project/projectReducer';
4
+ import { updateSectionProjectView } from '../../entity/sectionProjectView/sectionProjectViewReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
6
+ import { fetchProfitAndLossForTimeframeProjectView, updateProfitAndLossForTimeframeProjectView, updateProfitAndLossForTimeframeProjectViewFailure, } from './profitAndLossProjectViewReducer';
7
+ export const fetchProfitAndLossForTimeframeProjectViewEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchProfitAndLossForTimeframeProjectView.match), mergeMap((action) => {
8
+ const getTimeSeriesGroup = (timeframe) => {
9
+ switch (timeframe) {
10
+ case 'month':
11
+ return 'months';
12
+ case 'quarter':
13
+ return 'quarters';
14
+ case 'year':
15
+ return 'years';
16
+ }
17
+ };
18
+ const queryValue = {
19
+ is_full_response: action.payload.fetchFullReport,
20
+ time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
21
+ is_group_by_project: true,
22
+ };
23
+ return zeniAPI
24
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/2.0/reports/profit_and_loss?query=${encodeURIComponent(JSON.stringify(queryValue))}`)
25
+ .pipe(mergeMap((response) => {
26
+ if (response.data != null && isSuccessResponse(response)) {
27
+ const actions = [];
28
+ const report = response.data.report;
29
+ const currency = report.currency;
30
+ actions.push(updateProjects(report.projects));
31
+ actions.push(updateSectionProjectView(action.payload.timeframe, 'cogs', 'profit_and_loss_by_projects', report.cogs, report.accounts, currency));
32
+ actions.push(updateSectionProjectView(action.payload.timeframe, 'expenses', 'profit_and_loss_by_projects', report.expenses, report.accounts, currency));
33
+ actions.push(updateSectionProjectView(action.payload.timeframe, 'income', 'profit_and_loss_by_projects', report.income, report.accounts, currency));
34
+ actions.push(updateSectionProjectView(action.payload.timeframe, 'otherExpenses', 'profit_and_loss_by_projects', report.other_expenses, report.accounts, currency));
35
+ actions.push(updateSectionProjectView(action.payload.timeframe, 'otherIncome', 'profit_and_loss_by_projects', report.other_income, report.accounts, currency));
36
+ actions.push(updateProfitAndLossForTimeframeProjectView({
37
+ timeframe: action.payload.timeframe,
38
+ report: response.data,
39
+ }));
40
+ return from(actions);
41
+ }
42
+ else {
43
+ return of(updateProfitAndLossForTimeframeProjectViewFailure(response.status, action.payload.timeframe));
44
+ }
45
+ }), catchError((error) => of(updateProfitAndLossForTimeframeProjectViewFailure(createZeniAPIStatus('Unexpected Error', 'P&L by Projects REST API call errored out' +
46
+ JSON.stringify(error)), action.payload.timeframe))));
47
+ }));
@@ -0,0 +1,30 @@
1
+ import { from } from 'rxjs';
2
+ import { filter, switchMap } from 'rxjs/operators';
3
+ import { fetchProfitAndLossForTimeframeProjectView, fetchProfitAndLossProjectView, } from './profitAndLossProjectViewReducer';
4
+ export const fetchProfitAndLossProjectViewEpic = (actions$, state) => actions$.pipe(filter(fetchProfitAndLossProjectView.match), switchMap((action) => {
5
+ const { cacheOverride } = action.payload;
6
+ if (cacheOverride === true) {
7
+ return from([
8
+ fetchProfitAndLossForTimeframeProjectView('month'),
9
+ fetchProfitAndLossForTimeframeProjectView('quarter'),
10
+ fetchProfitAndLossForTimeframeProjectView('year'),
11
+ ]);
12
+ }
13
+ else {
14
+ const fetchActions = [];
15
+ const projectFetchState = state.value.profitAndLossProjectViewState.fetchState;
16
+ if (projectFetchState['month'].fetchState !== 'In-Progress' &&
17
+ projectFetchState['month'].fetchState !== 'Completed') {
18
+ fetchActions.push(fetchProfitAndLossForTimeframeProjectView('month'));
19
+ }
20
+ if (projectFetchState['quarter'].fetchState !== 'In-Progress' &&
21
+ projectFetchState['quarter'].fetchState !== 'Completed') {
22
+ fetchActions.push(fetchProfitAndLossForTimeframeProjectView('quarter'));
23
+ }
24
+ if (projectFetchState['year'].fetchState !== 'In-Progress' &&
25
+ projectFetchState['year'].fetchState !== 'Completed') {
26
+ fetchActions.push(fetchProfitAndLossForTimeframeProjectView('year'));
27
+ }
28
+ return from(fetchActions);
29
+ }
30
+ }));