@zeniai/client-epic-state 4.20.7 → 4.20.9-beta0ND

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 (193) hide show
  1. package/lib/commonStateTypes/coaBalance/additionalBalances/getSummationBalance.d.ts +1 -1
  2. package/lib/commonStateTypes/coaBalance/coaBalanceType.d.ts +2 -0
  3. package/lib/commonStateTypes/coaBalance/coaBalanceType.js +6 -0
  4. package/lib/commonStateTypes/currencyHelper.d.ts +3 -0
  5. package/lib/commonStateTypes/currencyHelper.js +6 -1
  6. package/lib/commonStateTypes/reduceFetchState.d.ts +9 -0
  7. package/lib/commonStateTypes/reduceFetchState.js +26 -0
  8. package/lib/coreEpics.js +2 -1
  9. package/lib/entity/account/accountPayload.d.ts +2 -0
  10. package/lib/entity/account/accountPayload.js +2 -0
  11. package/lib/entity/account/accountState.d.ts +2 -0
  12. package/lib/entity/customer/customerState.d.ts +0 -2
  13. package/lib/entity/customer/customerState.js +0 -5
  14. package/lib/entity/depositAccount/depositAccount.d.ts +1 -1
  15. package/lib/entity/depositAccount/depositAccount.js +8 -1
  16. package/lib/entity/reimbursement/reimbursementPayload.d.ts +2 -0
  17. package/lib/entity/reimbursement/reimbursementPayload.js +7 -0
  18. package/lib/entity/reimbursement/reimbursementState.d.ts +2 -0
  19. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  20. package/lib/entity/snackbar/snackbarTypes.js +2 -0
  21. package/lib/entity/task/taskPayload.d.ts +1 -0
  22. package/lib/entity/task/taskPayload.js +1 -0
  23. package/lib/entity/task/taskState.d.ts +1 -0
  24. package/lib/entity/tenant/SessionManager.d.ts +38 -0
  25. package/lib/entity/tenant/SessionManager.js +171 -0
  26. package/lib/entity/tenant/epic/sessionHeartbeatEpic.d.ts +16 -0
  27. package/lib/entity/tenant/epic/sessionHeartbeatEpic.js +16 -0
  28. package/lib/entity/tenant/sessionTypes.d.ts +26 -0
  29. package/lib/entity/tenant/sessionTypes.js +12 -0
  30. package/lib/entity/tenant/tenantReducer.d.ts +5 -1
  31. package/lib/entity/tenant/tenantReducer.js +23 -2
  32. package/lib/entity/tenant/tenantState.d.ts +1 -0
  33. package/lib/entity/userGroups/userGroupsPayload.d.ts +7 -0
  34. package/lib/entity/userGroups/userGroupsPayload.js +10 -0
  35. package/lib/entity/userGroups/userGroupsReducer.d.ts +8 -0
  36. package/lib/entity/userGroups/userGroupsReducer.js +29 -0
  37. package/lib/entity/userGroups/userGroupsSelector.d.ts +4 -0
  38. package/lib/entity/userGroups/userGroupsSelector.js +12 -0
  39. package/lib/entity/userGroups/userGroupsState.d.ts +9 -0
  40. package/lib/entity/userGroups/userGroupsState.js +2 -0
  41. package/lib/epic.d.ts +15 -1
  42. package/lib/epic.js +15 -1
  43. package/lib/esm/commonStateTypes/coaBalance/coaBalanceType.js +5 -0
  44. package/lib/esm/commonStateTypes/currencyHelper.js +5 -0
  45. package/lib/esm/commonStateTypes/reduceFetchState.js +25 -0
  46. package/lib/esm/coreEpics.js +2 -1
  47. package/lib/esm/entity/account/accountPayload.js +2 -0
  48. package/lib/esm/entity/customer/customerState.js +1 -4
  49. package/lib/esm/entity/depositAccount/depositAccount.js +8 -1
  50. package/lib/esm/entity/reimbursement/reimbursementPayload.js +7 -0
  51. package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
  52. package/lib/esm/entity/task/taskPayload.js +1 -0
  53. package/lib/esm/entity/tenant/SessionManager.js +167 -0
  54. package/lib/esm/entity/tenant/epic/sessionHeartbeatEpic.js +12 -0
  55. package/lib/esm/entity/tenant/sessionTypes.js +9 -0
  56. package/lib/esm/entity/tenant/tenantReducer.js +21 -1
  57. package/lib/esm/entity/userGroups/userGroupsPayload.js +7 -0
  58. package/lib/esm/entity/userGroups/userGroupsReducer.js +25 -0
  59. package/lib/esm/entity/userGroups/userGroupsSelector.js +8 -0
  60. package/lib/esm/entity/userGroups/userGroupsState.js +1 -0
  61. package/lib/esm/epic.js +15 -1
  62. package/lib/esm/index.js +24 -12
  63. package/lib/esm/reducer.js +6 -0
  64. package/lib/esm/view/arAgingView/arAgingReport/arAgingReducer.js +1 -1
  65. package/lib/esm/view/arAgingView/arAgingReport/arAgingSelector.js +1 -1
  66. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadMatchResultToastEpic.js +33 -0
  67. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +29 -0
  68. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +49 -0
  69. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +40 -0
  70. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +49 -0
  71. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +61 -0
  72. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +33 -0
  73. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +56 -0
  74. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/refetchCompletedTransactionsOnBulkUploadSortEpic.js +12 -0
  75. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/restoreBulkUploadAutomatchingOnMountEpic.js +98 -0
  76. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +71 -0
  77. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +7 -5
  78. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +86 -0
  79. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +24 -0
  80. package/lib/esm/view/expenseAutomationView/helpers/bulkUploadTiming.js +16 -0
  81. package/lib/esm/view/expenseAutomationView/helpers/rollingCalendarDateRangeInclusive.js +13 -0
  82. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +198 -1
  83. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +456 -2
  84. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +23 -1
  85. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +246 -1
  86. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +2 -1
  87. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +44 -0
  88. package/lib/esm/view/expenseAutomationView/types/transactionsViewState.js +2 -1
  89. package/lib/esm/view/financeStatement/financeStatementReducer.js +11 -8
  90. package/lib/esm/view/financeStatement/financeStatementSelector.js +24 -9
  91. package/lib/esm/view/profitAndLossClassesView/horizontalSectionEmptyBalancesSlice.js +17 -0
  92. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +331 -0
  93. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +9 -0
  94. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +6 -1
  95. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
  96. package/lib/esm/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
  97. package/lib/esm/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +262 -0
  98. package/lib/esm/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +9 -7
  99. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  100. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +1 -0
  101. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +3 -1
  102. package/lib/esm/view/userGroupListView/userGroupListViewReducer.js +65 -0
  103. package/lib/esm/view/userGroupListView/userGroupListViewSelector.js +16 -0
  104. package/lib/esm/view/userGroupListView/userGroupListViewState.js +1 -0
  105. package/lib/esm/view/userListView/fetchUserListByTypeEpic.js +11 -0
  106. package/lib/esm/zeniAPI.js +0 -2
  107. package/lib/index.d.ts +25 -14
  108. package/lib/index.js +100 -31
  109. package/lib/reducer.d.ts +6 -0
  110. package/lib/reducer.js +6 -0
  111. package/lib/tsconfig.typecheck.tsbuildinfo +1 -0
  112. package/lib/view/arAgingView/arAgingReport/arAgingReducer.js +2 -2
  113. package/lib/view/arAgingView/arAgingReport/arAgingSelector.js +5 -5
  114. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadMatchResultToastEpic.d.ts +13 -0
  115. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadMatchResultToastEpic.js +37 -0
  116. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +18 -0
  117. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +33 -0
  118. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +7 -0
  119. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +53 -0
  120. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.d.ts +8 -0
  121. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +44 -0
  122. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +7 -0
  123. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +53 -0
  124. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.d.ts +8 -0
  125. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +65 -0
  126. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.d.ts +8 -0
  127. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +37 -0
  128. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.d.ts +9 -0
  129. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +61 -0
  130. package/lib/view/expenseAutomationView/epics/missingReceipts/refetchCompletedTransactionsOnBulkUploadSortEpic.d.ts +10 -0
  131. package/lib/view/expenseAutomationView/epics/missingReceipts/refetchCompletedTransactionsOnBulkUploadSortEpic.js +16 -0
  132. package/lib/view/expenseAutomationView/epics/missingReceipts/restoreBulkUploadAutomatchingOnMountEpic.d.ts +18 -0
  133. package/lib/view/expenseAutomationView/epics/missingReceipts/restoreBulkUploadAutomatchingOnMountEpic.js +102 -0
  134. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.d.ts +14 -0
  135. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +75 -0
  136. package/lib/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +7 -5
  137. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +25 -0
  138. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +92 -0
  139. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.d.ts +7 -0
  140. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +28 -0
  141. package/lib/view/expenseAutomationView/helpers/bulkUploadTiming.d.ts +16 -0
  142. package/lib/view/expenseAutomationView/helpers/bulkUploadTiming.js +19 -0
  143. package/lib/view/expenseAutomationView/helpers/rollingCalendarDateRangeInclusive.d.ts +7 -0
  144. package/lib/view/expenseAutomationView/helpers/rollingCalendarDateRangeInclusive.js +16 -0
  145. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  146. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +123 -0
  147. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +211 -0
  148. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +86 -3
  149. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +457 -2
  150. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +11 -3
  151. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +24 -2
  152. package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +71 -1
  153. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +1 -0
  154. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.d.ts +1 -1
  155. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +245 -0
  156. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +2 -1
  157. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +146 -0
  158. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +54 -1
  159. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -1
  160. package/lib/view/expenseAutomationView/types/transactionsViewState.js +2 -1
  161. package/lib/view/financeStatement/financeStatementReducer.js +11 -8
  162. package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
  163. package/lib/view/financeStatement/financeStatementSelector.js +24 -9
  164. package/lib/view/profitAndLossClassesView/horizontalSectionEmptyBalancesSlice.d.ts +9 -0
  165. package/lib/view/profitAndLossClassesView/horizontalSectionEmptyBalancesSlice.js +20 -0
  166. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +15 -0
  167. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +335 -0
  168. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.d.ts +111 -0
  169. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +13 -0
  170. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.d.ts +4 -2
  171. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +7 -2
  172. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
  173. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +4 -0
  174. package/lib/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
  175. package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.d.ts +6 -0
  176. package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +265 -0
  177. package/lib/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +8 -6
  178. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  179. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +1 -0
  180. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +1 -0
  181. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +2 -0
  182. package/lib/view/taskManager/taskListView/taskListSelector.js +3 -1
  183. package/lib/view/userGroupListView/userGroupListViewReducer.d.ts +23 -0
  184. package/lib/view/userGroupListView/userGroupListViewReducer.js +69 -0
  185. package/lib/view/userGroupListView/userGroupListViewSelector.d.ts +7 -0
  186. package/lib/view/userGroupListView/userGroupListViewSelector.js +20 -0
  187. package/lib/view/userGroupListView/userGroupListViewState.d.ts +8 -0
  188. package/lib/view/userGroupListView/userGroupListViewState.js +2 -0
  189. package/lib/view/userListView/fetchUserListByTypeEpic.d.ts +3 -1
  190. package/lib/view/userListView/fetchUserListByTypeEpic.js +11 -0
  191. package/lib/view/userListView/userListViewPayload.d.ts +2 -0
  192. package/lib/zeniAPI.js +0 -2
  193. package/package.json +3 -3
@@ -0,0 +1,262 @@
1
+ import { defaultCustomerCurrency } from '../../commonStateTypes/currencyHelper';
2
+ import { getEmptyHorizontalSectionBalancesSlice } from './horizontalSectionEmptyBalancesSlice';
3
+ import { HORIZONTAL_CLASS_TOTAL_BALANCE_ID, } from './profitAndLossClassesByClassHorizontalSelectorTypes';
4
+ /**
5
+ * Populates `sectionHeaderBalancesSlice`, and per-account `accountReportData`, so the
6
+ * web layer only maps selector output to tree nodes.
7
+ */
8
+ export function enrichProfitAndLossByClassHorizontalReport(report) {
9
+ if (report.fetchState !== 'Completed' || report.selectedPeriod == null) {
10
+ return;
11
+ }
12
+ for (const section of Object.values(report.sections)) {
13
+ if (section != null) {
14
+ enrichHorizontalSection(report, section);
15
+ }
16
+ }
17
+ for (const calc of Object.values(report.calculatedSections)) {
18
+ if (calc != null) {
19
+ enrichHorizontalCalculatedSection(report, calc);
20
+ }
21
+ }
22
+ }
23
+ function enrichHorizontalSection(report, section) {
24
+ const classAmounts = report.classColumns.map((col) => {
25
+ const total = section.classTotals.find((ct) => ct.classId === col.classId);
26
+ return total?.balance.amount ?? 0;
27
+ });
28
+ section.sectionHeaderBalancesSlice = buildHorizontalClassColumnBalancesSlice(report, classAmounts, section.sectionTotal.amount);
29
+ const parentIndices = computeHorizontalAccountParentIndices(section.accounts);
30
+ const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(parentIndices);
31
+ const childrenRecord = {};
32
+ childrenRowIndicesByParent.forEach((childIndices, parentIndex) => {
33
+ childrenRecord[parentIndex] = childIndices;
34
+ });
35
+ section.treeLayout = {
36
+ rootAccountRowIndices: section.accounts
37
+ .map((_, i) => (parentIndices[i] === -1 ? i : -1))
38
+ .filter((i) => i >= 0),
39
+ childrenRowIndicesByParent: childrenRecord,
40
+ };
41
+ const siblingsPerRow = buildSiblingIndicesPerRow(section.accounts, parentIndices);
42
+ const hasChildFlags = computeHorizontalHasChildFlags(parentIndices);
43
+ for (let accountIndex = 0; accountIndex < section.accounts.length; accountIndex++) {
44
+ const row = section.accounts[accountIndex];
45
+ // Same column order as `report.classColumns` (see `pivotSectionToHorizontal`).
46
+ const classRowAmounts = row.classBalances.map((classBalance) => classBalance.balance.amount);
47
+ row.accountReportData = {
48
+ accountId: row.accountId,
49
+ accountName: row.accountName,
50
+ accountType: row.accountType,
51
+ depth: row.depth,
52
+ balancesInTimeframe: buildHorizontalClassColumnBalancesSlice(report, classRowAmounts, row.rowTotal.amount),
53
+ horizontalTreeView: buildHorizontalTreeViewFromPrecomputed(section.accounts, accountIndex, parentIndices, siblingsPerRow, hasChildFlags),
54
+ };
55
+ }
56
+ }
57
+ function enrichHorizontalCalculatedSection(report, calcSection) {
58
+ const classAmounts = report.classColumns.map((col) => {
59
+ const total = calcSection.classTotals.find((ct) => ct.classId === col.classId);
60
+ return total?.balance.amount ?? 0;
61
+ });
62
+ calcSection.sectionHeaderBalancesSlice =
63
+ buildHorizontalClassColumnBalancesSlice(report, classAmounts, calcSection.sectionTotal.amount);
64
+ }
65
+ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmount) {
66
+ const fallback = defaultCustomerCurrency;
67
+ const firstHeader = report.headerBalances[0];
68
+ const currencyCode = firstHeader?.balance.currencyCode ?? fallback.currencyCode;
69
+ const currencySymbol = firstHeader?.balance.currencySymbol ?? fallback.currencySymbol;
70
+ const timeframe = firstHeader?.balanceTimeFrame ?? 'month';
71
+ if (report.selectedPeriod == null) {
72
+ return getEmptyHorizontalSectionBalancesSlice(report.firstMonthOfFY, timeframe);
73
+ }
74
+ const { startDate, endDate } = report.selectedPeriod;
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
+ });
91
+ balances.push({
92
+ balance: {
93
+ amount: totalAmount,
94
+ currencyCode,
95
+ currencySymbol,
96
+ },
97
+ balanceTimeFrame: timeframe,
98
+ startDate,
99
+ endDate,
100
+ type: totalAmount === 0 ? 'default_with_null_balance' : 'default',
101
+ id: HORIZONTAL_CLASS_TOTAL_BALANCE_ID,
102
+ label: 'Total',
103
+ });
104
+ return {
105
+ balances,
106
+ additionalBalances: [],
107
+ filter: {
108
+ firstMonthOfFY: report.firstMonthOfFY,
109
+ timeframe,
110
+ balancesRange: {
111
+ numberOfPeriods: balances.length,
112
+ orderBy: 'ascending_date',
113
+ },
114
+ additionalBalances: [],
115
+ },
116
+ };
117
+ }
118
+ /**
119
+ * Parent index per DFS row — O(n). Matches the scan in the former
120
+ * `findHorizontalAccountParentIndex` (depth &lt;= 2 rows have no parent).
121
+ */
122
+ function computeHorizontalAccountParentIndices(rows) {
123
+ const accountRowCount = rows.length;
124
+ const parentIndex = new Array(accountRowCount).fill(-1);
125
+ const stack = [];
126
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
127
+ const accountRow = rows[rowIndex];
128
+ if (accountRow == null) {
129
+ continue;
130
+ }
131
+ const depth = accountRow.depth;
132
+ while (stack.length > 0) {
133
+ const topRow = rows[stack[stack.length - 1]];
134
+ if (topRow == null) {
135
+ stack.pop();
136
+ continue;
137
+ }
138
+ if (topRow.depth < depth) {
139
+ break;
140
+ }
141
+ stack.pop();
142
+ }
143
+ if (depth > 2 && stack.length > 0) {
144
+ const peek = stack[stack.length - 1];
145
+ const parentRow = rows[peek];
146
+ if (parentRow != null && parentRow.depth === depth - 1) {
147
+ parentIndex[rowIndex] = peek;
148
+ }
149
+ }
150
+ stack.push(rowIndex);
151
+ }
152
+ return parentIndex;
153
+ }
154
+ /** Sibling row indices (same parent + depth), in traversal order — O(n). */
155
+ function buildSiblingIndicesPerRow(rows, parentIndices) {
156
+ const accountRowCount = rows.length;
157
+ const keyToIndices = new Map();
158
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
159
+ const parentRowIndex = parentIndices[rowIndex];
160
+ const accountRow = rows[rowIndex];
161
+ if (parentRowIndex == null || accountRow == null) {
162
+ continue;
163
+ }
164
+ const key = `${parentRowIndex}:${accountRow.depth}`;
165
+ let siblingGroup = keyToIndices.get(key);
166
+ if (siblingGroup == null) {
167
+ siblingGroup = [];
168
+ keyToIndices.set(key, siblingGroup);
169
+ }
170
+ siblingGroup.push(rowIndex);
171
+ }
172
+ const siblingsPerRow = new Array(accountRowCount);
173
+ for (let rowIndex = 0; rowIndex < accountRowCount; rowIndex++) {
174
+ const parentRowIndex = parentIndices[rowIndex];
175
+ const accountRow = rows[rowIndex];
176
+ if (parentRowIndex == null || accountRow == null) {
177
+ siblingsPerRow[rowIndex] = [rowIndex];
178
+ continue;
179
+ }
180
+ const key = `${parentRowIndex}:${accountRow.depth}`;
181
+ const group = keyToIndices.get(key);
182
+ siblingsPerRow[rowIndex] = group != null ? group : [rowIndex];
183
+ }
184
+ return siblingsPerRow;
185
+ }
186
+ function computeHorizontalHasChildFlags(parentIndices) {
187
+ const rowCount = parentIndices.length;
188
+ const flags = new Array(rowCount).fill(false);
189
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
190
+ const parentRowIndex = parentIndices[rowIndex];
191
+ if (parentRowIndex != null &&
192
+ parentRowIndex >= 0 &&
193
+ parentRowIndex < rowCount) {
194
+ flags[parentRowIndex] = true;
195
+ }
196
+ }
197
+ return flags;
198
+ }
199
+ function buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
200
+ const chain = [];
201
+ let walkRowIndex = currentRowIndex;
202
+ while (walkRowIndex >= 0) {
203
+ chain.unshift(walkRowIndex);
204
+ const parentRowIndex = parentIndices[walkRowIndex];
205
+ if (parentRowIndex == null) {
206
+ break;
207
+ }
208
+ walkRowIndex = parentRowIndex;
209
+ }
210
+ return chain.map((rowIndex) => {
211
+ const accountRow = dfsOrderedAccountRows[rowIndex];
212
+ const siblingIndices = siblingsPerRow[rowIndex];
213
+ const hasChild = hasChildFlags[rowIndex];
214
+ if (accountRow == null || siblingIndices == null) {
215
+ return {
216
+ depth: 0,
217
+ hasSibling: false,
218
+ hasChildren: hasChild === true,
219
+ isLastNode: true,
220
+ name: '',
221
+ };
222
+ }
223
+ return {
224
+ depth: accountRow.depth - 2,
225
+ hasSibling: siblingIndices.length > 1,
226
+ hasChildren: hasChild === true,
227
+ isLastNode: rowIndex === siblingIndices[siblingIndices.length - 1],
228
+ name: accountRow.accountName,
229
+ };
230
+ });
231
+ }
232
+ function buildHorizontalTreeViewFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
233
+ const siblingIndices = siblingsPerRow[currentRowIndex];
234
+ const accountRow = dfsOrderedAccountRows[currentRowIndex];
235
+ const hasChildrenFlag = hasChildFlags[currentRowIndex];
236
+ const treeDepth = accountRow != null ? Math.max(0, accountRow.depth - 2) : 0;
237
+ const hasChildren = hasChildrenFlag === true;
238
+ const siblings = siblingIndices ?? [currentRowIndex];
239
+ return {
240
+ subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags),
241
+ treeDepth,
242
+ hasChildren,
243
+ hasSiblings: siblings.length > 1,
244
+ isLeaf: !hasChildren,
245
+ isLastNode: currentRowIndex === siblings[siblings.length - 1],
246
+ };
247
+ }
248
+ function buildHorizontalAccountChildIndicesByParent(parentIndices) {
249
+ const childIndicesByParentRowIndex = new Map();
250
+ for (let rowIndex = 0; rowIndex < parentIndices.length; rowIndex++) {
251
+ const parentRowIndex = parentIndices[rowIndex];
252
+ if (parentRowIndex != null && parentRowIndex >= 0) {
253
+ let childRowIndices = childIndicesByParentRowIndex.get(parentRowIndex);
254
+ if (childRowIndices == null) {
255
+ childRowIndices = [];
256
+ childIndicesByParentRowIndex.set(parentRowIndex, childRowIndices);
257
+ }
258
+ childRowIndices.push(rowIndex);
259
+ }
260
+ }
261
+ return childIndicesByParentRowIndex;
262
+ }
@@ -2,15 +2,19 @@ import { of } from 'rxjs';
2
2
  import { filter, switchMap } from 'rxjs/operators';
3
3
  import { updateCashInCashOutCOABalancesRange } from '../cashInCashOut/cashInCashOutReducer';
4
4
  import { updateCashPositionCOABalancesRange } from '../cashPosition/cashPositionReducer';
5
- import { initialFinanceStatementState, updateCOABalancesRange, } from '../financeStatement/financeStatementReducer';
5
+ import { updateCOABalancesRange } from '../financeStatement/financeStatementReducer';
6
6
  import { updateNetBurnOrIncomeCOABalancesRange } from '../netBurnOrIncome/netBurnOrIncomeReducer';
7
7
  import { updateOpExCOABalancesRange } from '../opEx/opExReducer';
8
8
  import { updateRevenueCOABalancesRange } from '../revenue/revenueReducer';
9
9
  import { updateReportUIOptionCOABalancesRange } from './reportUIOptionsReducer';
10
10
  export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => actions$.pipe(filter(updateReportUIOptionCOABalancesRange.match), switchMap((action) => {
11
- const thisPeriod = action.payload.selectedCOABalancesRange.thisPeriod;
12
- const orderBy = action.payload.selectedCOABalancesRange.orderBy;
13
- const highlightedNoOfPeriods = state$.value.reportUIOptionsState.isCompareModeOn === true ? 4 : 1;
11
+ const selectedRange = action.payload.selectedCOABalancesRange;
12
+ const thisPeriod = selectedRange.thisPeriod;
13
+ const orderBy = selectedRange.orderBy;
14
+ const numberOfPeriodsFromSelection = selectedRange.numberOfPeriods;
15
+ const highlightedNoOfPeriods = state$.value.reportUIOptionsState.isCompareModeOn === true
16
+ ? numberOfPeriodsFromSelection
17
+ : 1;
14
18
  const highlightedCOABalancesRange = action.payload.highlightedCOABalancesRange == null && thisPeriod != null
15
19
  ? {
16
20
  numberOfPeriods: highlightedNoOfPeriods,
@@ -62,9 +66,7 @@ export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => ac
62
66
  thisPeriod: action.payload.highlightedCOABalancesRange != null
63
67
  ? action.payload.highlightedCOABalancesRange.thisPeriod
64
68
  : thisPeriod,
65
- numberOfPeriods: state$.value.reportUIOptionsState.isCompareModeOn === true
66
- ? 4
67
- : initialFinanceStatementState.maxNumOfPeriodsToHighlight,
69
+ numberOfPeriods: numberOfPeriodsFromSelection,
68
70
  orderBy,
69
71
  }));
70
72
  }));
@@ -109,7 +109,7 @@ export const allTaskPriority = [
109
109
  },
110
110
  {
111
111
  code: 'medium',
112
- name: 'Normal',
112
+ name: 'Medium',
113
113
  },
114
114
  {
115
115
  code: 'low',
@@ -70,6 +70,7 @@ const toTaskPayload = (state, task) => {
70
70
  name: task.name,
71
71
  assignees: task.assignees,
72
72
  description: task.description,
73
+ group_assignees: task.groupAssignees,
73
74
  due_date: task.dueDate != null ? task.dueDate.format(DEFAULT_DATE_FORMAT) : null,
74
75
  priority: task.priority.code,
75
76
  status: task.status.code,
@@ -11,6 +11,7 @@ import { getTaskGroupTemplateByIds } from '../../../entity/taskGroupTemplate/tas
11
11
  import { getUserName, getUsersByUserIds, } from '../../../entity/user/userSelector';
12
12
  import { getUserAndUserRole, } from '../../companyView/types/userAndRole';
13
13
  import { applyAdvancedFiltersOnList } from '../../spendManagement/spendManagementFilterHelpers';
14
+ import { getUserGroupList } from '../../userGroupListView/userGroupListViewSelector';
14
15
  import { getUserList, } from '../../userListView/userListViewSelector';
15
16
  import { allTaskPriority, allTaskStatus, } from '../taskDetailView/taskDetailSelector';
16
17
  import { DUE_DATE_GROUP_KEYS, } from './taskList';
@@ -308,7 +309,7 @@ const getTaskGroupsWithTaskList = ({ taskListState, taskState, userState, userRo
308
309
  tagState,
309
310
  });
310
311
  };
311
- export const getAllTasks = createSelector((state) => state.taskListState, (state) => state.taskState, (state) => state.userState, (state) => state.userRoleState, (state) => state.userListViewState, (state) => state.addressState, (state) => state.taskGroupState, (state) => state.taskGroupViewState, (state) => state.tagViewState, (state) => state.tagState, (state) => state.taskGroupTemplateState, (state) => state.taskGroupTemplateViewState, (_state, isTaskTemplatesEnabled) => isTaskTemplatesEnabled, (taskListState, taskState, userState, userRoleState, userListViewState, addressState, taskGroupState, taskGroupViewState, tagViewState, tagState, taskGroupTemplateState, taskGroupTemplateViewState, isTaskTemplatesEnabled) => {
312
+ export const getAllTasks = createSelector((state) => state.taskListState, (state) => state.taskState, (state) => state.userState, (state) => state.userRoleState, (state) => state.userListViewState, (state) => state.addressState, (state) => state.taskGroupState, (state) => state.taskGroupViewState, (state) => state.tagViewState, (state) => state.tagState, (state) => state.taskGroupTemplateState, (state) => state.taskGroupTemplateViewState, (state) => state.userGroupsState, (state) => state.userGroupListViewState, (_state, isTaskTemplatesEnabled) => isTaskTemplatesEnabled, (taskListState, taskState, userState, userRoleState, userListViewState, addressState, taskGroupState, taskGroupViewState, tagViewState, tagState, taskGroupTemplateState, taskGroupTemplateViewState, userGroupsState, userGroupListViewState, isTaskTemplatesEnabled) => {
312
313
  const { localData } = taskListState;
313
314
  const taskGroupsWithTasksList = getTaskGroupsWithTaskList({
314
315
  taskListState,
@@ -336,6 +337,7 @@ export const getAllTasks = createSelector((state) => state.taskListState, (state
336
337
  taskGroupTemplates,
337
338
  fetchState: fetchState,
338
339
  userList: getUserList(userState, userRoleState, userListViewState, 'taskManagerCandidate'),
340
+ userGroupList: getUserGroupList(userGroupsState, userGroupListViewState, 'taskManagerCandidate'),
339
341
  error: error,
340
342
  version: 0,
341
343
  taskGroupsWithTasksList,
@@ -0,0 +1,65 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ const initialUserGroupList = {
3
+ ids: [],
4
+ fetchState: 'Not-Started',
5
+ error: undefined,
6
+ hasValidState() {
7
+ return this.fetchState == 'Completed';
8
+ },
9
+ };
10
+ export const initialState = {
11
+ userGroupListByType: {
12
+ taskManagerCandidate: initialUserGroupList,
13
+ },
14
+ };
15
+ const userGroupListView = createSlice({
16
+ name: 'userGroupListView',
17
+ initialState,
18
+ reducers: {
19
+ fetchUserGroupListByType: {
20
+ reducer(draft, action) {
21
+ const { userGroupType } = action.payload;
22
+ draft.userGroupListByType[userGroupType].fetchState = 'In-Progress';
23
+ draft.userGroupListByType[userGroupType].error = undefined;
24
+ },
25
+ prepare(userGroupType, cacheOverride = false) {
26
+ return {
27
+ payload: {
28
+ userGroupType,
29
+ cacheOverride,
30
+ },
31
+ };
32
+ },
33
+ },
34
+ updateUserGroupIds(draft, action) {
35
+ const { userGroupType, userGroupsPayload } = action.payload;
36
+ draft.userGroupListByType[userGroupType].fetchState = 'Completed';
37
+ draft.userGroupListByType[userGroupType].error = undefined;
38
+ draft.userGroupListByType[userGroupType].ids = userGroupsPayload.map((userGroup) => userGroup.id);
39
+ },
40
+ addUserGroupId(draft, action) {
41
+ const { userGroupType, id } = action.payload;
42
+ const index = draft.userGroupListByType[userGroupType].ids.indexOf(id);
43
+ if (index < 0) {
44
+ draft.userGroupListByType[userGroupType].ids.push(id);
45
+ }
46
+ },
47
+ removeUserGroupId(draft, action) {
48
+ const { userGroupType, id } = action.payload;
49
+ const index = draft.userGroupListByType[userGroupType].ids.indexOf(id);
50
+ if (index > -1) {
51
+ draft.userGroupListByType[userGroupType].ids.splice(index, 1);
52
+ }
53
+ },
54
+ updateUserGroupListFetchFailure(draft, action) {
55
+ const { userGroupType, status } = action.payload;
56
+ draft.userGroupListByType[userGroupType].fetchState = 'Error';
57
+ draft.userGroupListByType[userGroupType].error = status;
58
+ },
59
+ clearUserGroupListView(draft) {
60
+ Object.assign(draft, initialState);
61
+ },
62
+ },
63
+ });
64
+ export const { fetchUserGroupListByType, updateUserGroupIds, addUserGroupId, removeUserGroupId, updateUserGroupListFetchFailure, clearUserGroupListView, } = userGroupListView.actions;
65
+ export default userGroupListView.reducer;
@@ -0,0 +1,16 @@
1
+ import { getUserGroupByUserGroupId } from '../../entity/userGroups/userGroupsSelector';
2
+ export const getUserGroupList = (userGroupsState, userGroupListViewState, userGroupType) => {
3
+ const listState = userGroupListViewState.userGroupListByType[userGroupType];
4
+ return {
5
+ userGroups: getUserGroupListByIds(userGroupsState, userGroupListViewState, userGroupType),
6
+ fetchState: listState?.fetchState,
7
+ error: listState?.error,
8
+ version: 0,
9
+ };
10
+ };
11
+ function getUserGroupListByIds(userGroupsState, userGroupListViewState, type) {
12
+ const userGroupIds = userGroupListViewState.userGroupListByType[type].ids;
13
+ return userGroupIds
14
+ .map((id) => getUserGroupByUserGroupId(userGroupsState, id))
15
+ .filter((value) => value != null);
16
+ }
@@ -3,9 +3,11 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { updateAddresses } from '../../entity/address/addressReducer';
4
4
  import { getCurrentTenant, isZeniDomainTenant, } from '../../entity/tenant/tenantSelector';
5
5
  import { updateAllUsers } from '../../entity/user/userReducer';
6
+ import { updateAllUserGroups } from '../../entity/userGroups/userGroupsReducer';
6
7
  import { updateUserRoles } from '../../entity/userRole/userRoleReducer';
7
8
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
8
9
  import { updateChargeCardCount, updateDebitCardCount, } from '../spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer';
10
+ import { updateUserGroupIds } from '../userGroupListView/userGroupListViewReducer';
9
11
  import { fetchUserListByType, updateUserIds, updateUserListFetchFailure, } from './userListViewReducer';
10
12
  export const fetchUserListByTypeEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchUserListByType.match), mergeMap((action) => {
11
13
  const { userType, cacheOverride } = action.payload;
@@ -29,6 +31,15 @@ export const fetchUserListByTypeEpic = (actions$, state$, zeniAPI) => actions$.p
29
31
  usersPayload: response.data?.users ?? [],
30
32
  }),
31
33
  ];
34
+ if (response.data?.user_groups != null) {
35
+ userListAction.push(updateAllUserGroups({ userGroups: response.data.user_groups }));
36
+ if (userType === 'taskManagerCandidate') {
37
+ userListAction.push(updateUserGroupIds({
38
+ userGroupType: userType,
39
+ userGroupsPayload: response.data.user_groups,
40
+ }));
41
+ }
42
+ }
32
43
  if (userType === 'cardHolderCandidate') {
33
44
  userListAction.push(updateChargeCardCount(response.data?.cards_count_by_user_id ?? []));
34
45
  userListAction.push(updateDebitCardCount(response.data?.debit_cards_count_by_deposit_account_id ?? {}));
@@ -79,8 +79,6 @@ export class ZeniAPIClient {
79
79
  return from(promise);
80
80
  }
81
81
  postFormData(restEndPoint, formData, signal) {
82
- // Use apiHeaders for auth headers, then remove Content-Type
83
- // so the browser sets multipart/form-data with the correct boundary
84
82
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
85
83
  const { 'Content-Type': _contentType, ...headers } = this.apiHeaders();
86
84
  const promise = fetch(restEndPoint, {