@zeniai/client-epic-state 5.0.46 → 5.0.47-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 (144) hide show
  1. package/lib/commonStateTypes/recommendationBase.d.ts +2 -1
  2. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
  3. package/lib/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  4. package/lib/entity/account/accountState.d.ts +1 -1
  5. package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
  6. package/lib/entity/chargeCardRepayment/chargeCardRepayment.d.ts +1 -1
  7. package/lib/entity/class/classReducer.d.ts +4 -4
  8. package/lib/entity/class/classState.d.ts +1 -1
  9. package/lib/entity/creditAgent/creditAgentPayload.d.ts +41 -0
  10. package/lib/entity/creditAgent/creditAgentPayload.js +40 -0
  11. package/lib/entity/creditAgent/creditAgentReducer.d.ts +9 -0
  12. package/lib/entity/creditAgent/creditAgentReducer.js +37 -0
  13. package/lib/entity/creditAgent/creditAgentSelector.d.ts +3 -0
  14. package/lib/entity/creditAgent/creditAgentSelector.js +10 -0
  15. package/lib/entity/creditAgent/creditAgentState.d.ts +39 -0
  16. package/lib/entity/creditAgent/creditAgentState.js +17 -0
  17. package/lib/entity/forecast/forecastState.d.ts +1 -1
  18. package/lib/entity/project/projectPayload.d.ts +7 -0
  19. package/lib/entity/project/projectPayload.js +15 -1
  20. package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
  21. package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
  22. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
  23. package/lib/entity/sectionProjectView/sectionProjectView.d.ts +1 -1
  24. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +2 -2
  25. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  26. package/lib/entity/snackbar/snackbarTypes.js +3 -0
  27. package/lib/entity/tenant/SessionManager.d.ts +4 -0
  28. package/lib/entity/tenant/SessionManager.js +6 -0
  29. package/lib/entity/tenant/clearAllEpic.d.ts +6 -3
  30. package/lib/entity/tenant/clearAllEpic.js +8 -2
  31. package/lib/entity/transaction/payloadTypes/transactionLinePayload.d.ts +2 -0
  32. package/lib/entity/transaction/payloadTypes/transactionLinePayload.js +9 -0
  33. package/lib/entity/transaction/stateTypes/transactionLine.d.ts +2 -0
  34. package/lib/epic.d.ts +10 -1
  35. package/lib/epic.js +10 -1
  36. package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +1 -0
  37. package/lib/esm/entity/creditAgent/creditAgentPayload.js +36 -0
  38. package/lib/esm/entity/creditAgent/creditAgentReducer.js +33 -0
  39. package/lib/esm/entity/creditAgent/creditAgentSelector.js +6 -0
  40. package/lib/esm/entity/creditAgent/creditAgentState.js +13 -0
  41. package/lib/esm/entity/project/projectPayload.js +12 -0
  42. package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
  43. package/lib/esm/entity/tenant/SessionManager.js +6 -0
  44. package/lib/esm/entity/tenant/clearAllEpic.js +8 -2
  45. package/lib/esm/entity/transaction/payloadTypes/transactionLinePayload.js +9 -0
  46. package/lib/esm/epic.js +10 -1
  47. package/lib/esm/index.js +19 -10
  48. package/lib/esm/reducer.js +12 -3
  49. package/lib/esm/view/creditAgentView/buildCreditReportCsv.js +44 -0
  50. package/lib/esm/view/creditAgentView/creditAgentViewPayload.js +2 -0
  51. package/lib/esm/view/creditAgentView/creditAgentViewReducer.js +183 -0
  52. package/lib/esm/view/creditAgentView/creditAgentViewSelector.js +85 -0
  53. package/lib/esm/view/creditAgentView/creditAgentViewState.js +20 -0
  54. package/lib/esm/view/creditAgentView/epics/fetchCardProfilesEpic.js +20 -0
  55. package/lib/esm/view/creditAgentView/epics/fetchCreditAgentAccessEpic.js +13 -0
  56. package/lib/esm/view/creditAgentView/epics/fetchCreditAgentMacroEpic.js +19 -0
  57. package/lib/esm/view/creditAgentView/epics/saveCreditAgentMacroEpic.js +58 -0
  58. package/lib/esm/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.js +39 -0
  59. package/lib/esm/view/creditAgentView/epics/updateCardProfileEpic.js +62 -0
  60. package/lib/esm/view/projectList/fetchProjectListEpic.js +38 -0
  61. package/lib/esm/view/projectList/projectListPayload.js +1 -0
  62. package/lib/esm/view/projectList/projectListReducer.js +39 -0
  63. package/lib/esm/view/projectList/projectListSelector.js +9 -0
  64. package/lib/esm/view/projectList/projectListState.js +1 -0
  65. package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  66. package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  67. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -0
  68. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +14 -2
  69. package/lib/esm/view/transactionList/fetchTransactionListByProjectEpic.js +45 -0
  70. package/lib/esm/view/transactionList/parallelFetchProjectTransactionListEpic.js +32 -0
  71. package/lib/esm/view/transactionList/transactionListByProjectSelector.js +58 -0
  72. package/lib/esm/view/transactionList/transactionListReducer.js +83 -2
  73. package/lib/esm/view/transactionList/transactionListState.js +10 -0
  74. package/lib/index.d.ts +25 -14
  75. package/lib/index.js +86 -46
  76. package/lib/reducer.d.ts +12 -3
  77. package/lib/reducer.js +12 -3
  78. package/lib/tsconfig.typecheck.tsbuildinfo +1 -0
  79. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  80. package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
  81. package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
  82. package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
  83. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
  84. package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
  85. package/lib/view/creditAgentView/buildCreditReportCsv.d.ts +17 -0
  86. package/lib/view/creditAgentView/buildCreditReportCsv.js +47 -0
  87. package/lib/view/creditAgentView/creditAgentViewPayload.d.ts +9 -0
  88. package/lib/view/creditAgentView/creditAgentViewPayload.js +7 -0
  89. package/lib/view/creditAgentView/creditAgentViewReducer.d.ts +41 -0
  90. package/lib/view/creditAgentView/creditAgentViewReducer.js +187 -0
  91. package/lib/view/creditAgentView/creditAgentViewSelector.d.ts +20 -0
  92. package/lib/view/creditAgentView/creditAgentViewSelector.js +93 -0
  93. package/lib/view/creditAgentView/creditAgentViewState.d.ts +34 -0
  94. package/lib/view/creditAgentView/creditAgentViewState.js +22 -0
  95. package/lib/view/creditAgentView/epics/fetchCardProfilesEpic.d.ts +15 -0
  96. package/lib/view/creditAgentView/epics/fetchCardProfilesEpic.js +24 -0
  97. package/lib/view/creditAgentView/epics/fetchCreditAgentAccessEpic.d.ts +11 -0
  98. package/lib/view/creditAgentView/epics/fetchCreditAgentAccessEpic.js +17 -0
  99. package/lib/view/creditAgentView/epics/fetchCreditAgentMacroEpic.d.ts +15 -0
  100. package/lib/view/creditAgentView/epics/fetchCreditAgentMacroEpic.js +23 -0
  101. package/lib/view/creditAgentView/epics/saveCreditAgentMacroEpic.d.ts +29 -0
  102. package/lib/view/creditAgentView/epics/saveCreditAgentMacroEpic.js +62 -0
  103. package/lib/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.d.ts +30 -0
  104. package/lib/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.js +43 -0
  105. package/lib/view/creditAgentView/epics/updateCardProfileEpic.d.ts +37 -0
  106. package/lib/view/creditAgentView/epics/updateCardProfileEpic.js +66 -0
  107. package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
  108. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  109. package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
  110. package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
  111. package/lib/view/projectList/fetchProjectListEpic.d.ts +8 -0
  112. package/lib/view/projectList/fetchProjectListEpic.js +42 -0
  113. package/lib/view/projectList/projectListPayload.d.ts +7 -0
  114. package/lib/view/projectList/projectListPayload.js +2 -0
  115. package/lib/view/projectList/projectListReducer.d.ts +9 -0
  116. package/lib/view/projectList/projectListReducer.js +43 -0
  117. package/lib/view/projectList/projectListSelector.d.ts +8 -0
  118. package/lib/view/projectList/projectListSelector.js +13 -0
  119. package/lib/view/projectList/projectListState.d.ts +4 -0
  120. package/lib/view/projectList/projectListState.js +2 -0
  121. package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
  122. package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
  123. package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
  124. package/lib/view/topEx/topExSelector.d.ts +1 -1
  125. package/lib/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  126. package/lib/view/transactionDetail/epics/transactionDetailEpic.d.ts +2 -1
  127. package/lib/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  128. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -0
  129. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +3 -0
  130. package/lib/view/transactionDetail/transactionDetailSelector.js +13 -1
  131. package/lib/view/transactionDetail/transactionDetailState.d.ts +2 -0
  132. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +2 -0
  133. package/lib/view/transactionList/fetchTransactionListByProjectEpic.d.ts +8 -0
  134. package/lib/view/transactionList/fetchTransactionListByProjectEpic.js +52 -0
  135. package/lib/view/transactionList/parallelFetchProjectTransactionListEpic.d.ts +6 -0
  136. package/lib/view/transactionList/parallelFetchProjectTransactionListEpic.js +36 -0
  137. package/lib/view/transactionList/transactionListByProjectSelector.d.ts +22 -0
  138. package/lib/view/transactionList/transactionListByProjectSelector.js +66 -0
  139. package/lib/view/transactionList/transactionListPayload.d.ts +15 -0
  140. package/lib/view/transactionList/transactionListReducer.d.ts +25 -2
  141. package/lib/view/transactionList/transactionListReducer.js +83 -2
  142. package/lib/view/transactionList/transactionListState.d.ts +15 -0
  143. package/lib/view/transactionList/transactionListState.js +13 -1
  144. package/package.json +1 -1
@@ -0,0 +1,183 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ const initialTenantView = {
3
+ analyzeStatus: { fetchState: 'Not-Started' },
4
+ updateStatus: { fetchState: 'Not-Started' },
5
+ };
6
+ function getOrCreateTenantView(draft, tenantId) {
7
+ if (draft.tenantViewByTenantId[tenantId] == null) {
8
+ draft.tenantViewByTenantId[tenantId] = {
9
+ ...initialTenantView,
10
+ tenantId,
11
+ };
12
+ }
13
+ return draft.tenantViewByTenantId[tenantId];
14
+ }
15
+ export const initialCreditAgentViewState = {
16
+ access: {
17
+ fetchStatus: { fetchState: 'Not-Started' },
18
+ isAllowed: false,
19
+ },
20
+ macro: {
21
+ fetchStatus: { fetchState: 'Not-Started' },
22
+ updateStatus: { fetchState: 'Not-Started' },
23
+ },
24
+ profilesFetchStatus: { fetchState: 'Not-Started' },
25
+ tenantViewByTenantId: {},
26
+ uiState: {
27
+ filterText: '',
28
+ focus: 'All',
29
+ minScore: 0,
30
+ sortDir: 'asc',
31
+ sortKey: undefined,
32
+ },
33
+ };
34
+ const creditAgentView = createSlice({
35
+ name: 'creditAgentView',
36
+ initialState: initialCreditAgentViewState,
37
+ reducers: {
38
+ // ── Access ──
39
+ fetchCreditAgentAccess(draft) {
40
+ draft.access.fetchStatus = { fetchState: 'In-Progress' };
41
+ },
42
+ fetchCreditAgentAccessSuccess(draft, action) {
43
+ draft.access.fetchStatus = { fetchState: 'Completed' };
44
+ draft.access.isAllowed = action.payload;
45
+ },
46
+ fetchCreditAgentAccessFailure(draft, action) {
47
+ draft.access.fetchStatus = { fetchState: 'Error', error: action.payload };
48
+ },
49
+ // ── Card Profiles (list-level fetch) ──
50
+ fetchCardProfiles(draft) {
51
+ draft.profilesFetchStatus = { fetchState: 'In-Progress' };
52
+ },
53
+ fetchCardProfilesSuccess(draft, action) {
54
+ draft.profilesFetchStatus = { fetchState: 'Completed' };
55
+ // Replace entire tenantViewByTenantId, preserving existing statuses
56
+ // for tenants still present, removing stale ones.
57
+ draft.tenantViewByTenantId = toTenantViewByTenantId(action.payload, draft.tenantViewByTenantId);
58
+ },
59
+ fetchCardProfilesFailure(draft, action) {
60
+ draft.profilesFetchStatus = { fetchState: 'Error', error: action.payload };
61
+ },
62
+ // ── Update Card Profile (per-tenant) ──
63
+ updateCardProfile: {
64
+ reducer(draft, action) {
65
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
66
+ tv.updateStatus = { fetchState: 'In-Progress' };
67
+ },
68
+ prepare(payload) {
69
+ return { payload };
70
+ },
71
+ },
72
+ updateCardProfileSuccess: {
73
+ reducer(draft, action) {
74
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
75
+ tv.updateStatus = { fetchState: 'Completed' };
76
+ },
77
+ prepare(tenantId) {
78
+ return { payload: { tenantId } };
79
+ },
80
+ },
81
+ updateCardProfileFailure: {
82
+ reducer(draft, action) {
83
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
84
+ tv.updateStatus = {
85
+ fetchState: 'Error',
86
+ error: action.payload.error,
87
+ };
88
+ },
89
+ prepare(tenantId, error) {
90
+ return { payload: { tenantId, error } };
91
+ },
92
+ },
93
+ // ── Analyze / Schedule Cron (per-tenant) ──
94
+ scheduleTenantCreditScoreCron: {
95
+ reducer(draft, action) {
96
+ if (action.payload.tenantId != null) {
97
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
98
+ tv.analyzeStatus = { fetchState: 'In-Progress' };
99
+ }
100
+ },
101
+ prepare(tenantId) {
102
+ return { payload: { tenantId } };
103
+ },
104
+ },
105
+ scheduleTenantCreditScoreCronSuccess: {
106
+ reducer(draft, action) {
107
+ if (action.payload.tenantId != null) {
108
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
109
+ tv.analyzeStatus = { fetchState: 'Completed' };
110
+ }
111
+ },
112
+ prepare(tenantId) {
113
+ return { payload: { tenantId } };
114
+ },
115
+ },
116
+ scheduleTenantCreditScoreCronFailure: {
117
+ reducer(draft, action) {
118
+ if (action.payload.tenantId != null) {
119
+ const tv = getOrCreateTenantView(draft, action.payload.tenantId);
120
+ tv.analyzeStatus = {
121
+ fetchState: 'Error',
122
+ error: action.payload.error,
123
+ };
124
+ }
125
+ },
126
+ prepare(tenantId, error) {
127
+ return { payload: { tenantId, error } };
128
+ },
129
+ },
130
+ // ── Macro ──
131
+ fetchCreditAgentMacro(draft) {
132
+ draft.macro.fetchStatus = { fetchState: 'In-Progress' };
133
+ },
134
+ fetchCreditAgentMacroSuccess(draft) {
135
+ draft.macro.fetchStatus = { fetchState: 'Completed' };
136
+ },
137
+ fetchCreditAgentMacroFailure(draft, action) {
138
+ draft.macro.fetchStatus = { fetchState: 'Error', error: action.payload };
139
+ },
140
+ saveCreditAgentMacro: {
141
+ reducer(draft) {
142
+ draft.macro.updateStatus = { fetchState: 'In-Progress' };
143
+ },
144
+ prepare(instructions) {
145
+ return { payload: { instructions } };
146
+ },
147
+ },
148
+ saveCreditAgentMacroSuccess(draft) {
149
+ draft.macro.updateStatus = { fetchState: 'Completed' };
150
+ },
151
+ saveCreditAgentMacroFailure(draft, action) {
152
+ draft.macro.updateStatus = { fetchState: 'Error', error: action.payload };
153
+ },
154
+ resetSaveMacroState(draft) {
155
+ draft.macro.updateStatus = { fetchState: 'Not-Started' };
156
+ },
157
+ // ── UI State ──
158
+ updateCreditAgentUIState(draft, action) {
159
+ Object.assign(draft.uiState, action.payload);
160
+ },
161
+ // ── Clear ──
162
+ clearCreditAgentView() {
163
+ return initialCreditAgentViewState;
164
+ },
165
+ },
166
+ });
167
+ export const { fetchCreditAgentAccess, fetchCreditAgentAccessSuccess, fetchCreditAgentAccessFailure, scheduleTenantCreditScoreCron, scheduleTenantCreditScoreCronSuccess, scheduleTenantCreditScoreCronFailure, fetchCreditAgentMacro, fetchCreditAgentMacroSuccess, fetchCreditAgentMacroFailure, saveCreditAgentMacro, saveCreditAgentMacroSuccess, saveCreditAgentMacroFailure, resetSaveMacroState, fetchCardProfiles, fetchCardProfilesSuccess, fetchCardProfilesFailure, updateCardProfile, updateCardProfileSuccess, updateCardProfileFailure, updateCreditAgentUIState, clearCreditAgentView, } = creditAgentView.actions;
168
+ export { initialCreditAgentViewState as initialState };
169
+ export default creditAgentView.reducer;
170
+ // ── Helpers ──
171
+ const toTenantViewByTenantId = (rows, existing) => {
172
+ const result = {};
173
+ for (const row of rows) {
174
+ const tenantId = row.tenant_id;
175
+ const existingState = existing[tenantId];
176
+ result[tenantId] = existingState ?? {
177
+ analyzeStatus: { fetchState: 'Not-Started' },
178
+ tenantId,
179
+ updateStatus: { fetchState: 'Not-Started' },
180
+ };
181
+ }
182
+ return result;
183
+ };
@@ -0,0 +1,85 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+ import orderBy from 'lodash/orderBy';
3
+ export const getCreditAgentView = (state) => state.creditAgentViewState;
4
+ export const getCreditAgentEntity = (state) => state.creditAgentEntityState;
5
+ export const getCreditAgentMacro = createSelector(getCreditAgentView, getCreditAgentEntity, (view, entity) => ({
6
+ ...view.macro,
7
+ data: entity.macro,
8
+ }));
9
+ export const getCardProfilesData = createSelector(getCreditAgentView, getCreditAgentEntity, (view, entity) => {
10
+ const { uiState } = view;
11
+ const allRows = Object.values(entity.rowByTenantId).map((row) => {
12
+ const tenantView = view.tenantViewByTenantId[row.tenantId];
13
+ return {
14
+ ...row,
15
+ analyzeStatus: tenantView?.analyzeStatus ?? {
16
+ fetchState: 'Not-Started',
17
+ },
18
+ updateStatus: tenantView?.updateStatus ?? { fetchState: 'Not-Started' },
19
+ };
20
+ });
21
+ let filteredRows = allRows;
22
+ // Text filter
23
+ const trimmedFilterText = uiState.filterText.trim();
24
+ if (trimmedFilterText.length > 0) {
25
+ const query = trimmedFilterText.toLowerCase();
26
+ filteredRows = filteredRows.filter((row) => (row.customerName ?? '').toLowerCase().includes(query) ||
27
+ row.tenantId.toLowerCase().includes(query));
28
+ }
29
+ // Focus filter
30
+ filteredRows = applyFocusFilter(filteredRows, uiState.focus);
31
+ // Min score filter
32
+ if (uiState.minScore > 0) {
33
+ filteredRows = filteredRows.filter((row) => {
34
+ const score = parseFloat(row.creditScore ?? '0');
35
+ return score >= uiState.minScore;
36
+ });
37
+ }
38
+ // Sorting
39
+ const sortedRows = getSortedRows(filteredRows, uiState.sortKey, uiState.sortDir);
40
+ return {
41
+ fetchStatus: view.profilesFetchStatus,
42
+ rows: sortedRows,
43
+ uiState,
44
+ };
45
+ });
46
+ // ── Helpers ──
47
+ const applyFocusFilter = (rows, focus) => {
48
+ switch (focus) {
49
+ case 'New only':
50
+ return rows.filter((row) => row.isNew);
51
+ case 'Interested':
52
+ return rows.filter((row) => row.cardStatus === 'Interested');
53
+ case 'Active only':
54
+ return rows.filter((row) => row.cardStatus === 'Active' || row.cardStatus === 'Enabled');
55
+ case 'All':
56
+ default:
57
+ return rows;
58
+ }
59
+ };
60
+ const getSortedRows = (rows, sortKey, sortDir) => {
61
+ if (sortKey == null) {
62
+ return rows;
63
+ }
64
+ const direction = sortDir === 'asc' ? 'asc' : 'desc';
65
+ return orderBy(rows, (row) => {
66
+ switch (sortKey) {
67
+ case 'name':
68
+ return (row.customerName ?? '').toLowerCase();
69
+ case 'status':
70
+ return row.cardStatus.toLowerCase();
71
+ case 'creditLimit':
72
+ return row.creditLimit ?? 0;
73
+ case 'creditScore':
74
+ return parseFloat(row.creditScore ?? '0');
75
+ case 'recAmount':
76
+ return row.recommendedAmount ?? 0;
77
+ case 'reportDate':
78
+ return row.reportDate?.valueOf() ?? 0;
79
+ case 'updatedBy':
80
+ return (row.updatedByName ?? '').toLowerCase();
81
+ default:
82
+ return (row.customerName ?? '').toLowerCase();
83
+ }
84
+ }, direction);
85
+ };
@@ -0,0 +1,20 @@
1
+ import { stringToUnion } from '../../commonStateTypes/stringToUnion';
2
+ const ALL_CREDIT_AGENT_SORT_KEYS = [
3
+ 'name',
4
+ 'status',
5
+ 'creditLimit',
6
+ 'creditScore',
7
+ 'recAmount',
8
+ 'reportDate',
9
+ 'updatedBy',
10
+ ];
11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
+ const toCreditAgentSortKeyType = (v) => stringToUnion(v, ALL_CREDIT_AGENT_SORT_KEYS);
13
+ const ALL_CREDIT_AGENT_FOCUS_FILTERS = [
14
+ 'All',
15
+ 'New only',
16
+ 'Interested',
17
+ 'Active only',
18
+ ];
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
20
+ const toCreditAgentFocusFilterType = (v) => stringToUnion(v, ALL_CREDIT_AGENT_FOCUS_FILTERS);
@@ -0,0 +1,20 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateCreditAgentRows } from '../../../entity/creditAgent/creditAgentReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
+ import { fetchCardProfiles, fetchCardProfilesFailure, fetchCardProfilesSuccess, } from '../creditAgentViewReducer';
6
+ export const fetchCardProfilesEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardProfiles.match), switchMap(() => {
7
+ const url = `${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/cockpit/card-tenant-profiles`;
8
+ return zeniAPI.getJSON(url).pipe(mergeMap((response) => {
9
+ if (isSuccessResponse(response) && response.data != null) {
10
+ const rawRows = response.data.rows;
11
+ return from([
12
+ updateCreditAgentRows(rawRows),
13
+ fetchCardProfilesSuccess(rawRows),
14
+ ]);
15
+ }
16
+ else {
17
+ return of(fetchCardProfilesFailure(response.status));
18
+ }
19
+ }), catchError((error) => of(fetchCardProfilesFailure(createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))))));
20
+ }));
@@ -0,0 +1,13 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
4
+ import { fetchCreditAgentAccess, fetchCreditAgentAccessFailure, fetchCreditAgentAccessSuccess, } from '../creditAgentViewReducer';
5
+ export const fetchCreditAgentAccessEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCreditAgentAccess.match), switchMap(() => {
6
+ const url = `${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/cockpit/cards-cockpit-access`;
7
+ return zeniAPI.getJSON(url).pipe(switchMap((response) => {
8
+ if (isSuccessResponse(response) && response.data != null) {
9
+ return of(fetchCreditAgentAccessSuccess(response.data.is_allowed === true));
10
+ }
11
+ return of(fetchCreditAgentAccessFailure(response.status));
12
+ }), catchError((error) => of(fetchCreditAgentAccessFailure(createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))))));
13
+ }));
@@ -0,0 +1,19 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateCreditAgentMacro } from '../../../entity/creditAgent/creditAgentReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
5
+ import { fetchCreditAgentMacro, fetchCreditAgentMacroFailure, fetchCreditAgentMacroSuccess, } from '../creditAgentViewReducer';
6
+ export const fetchCreditAgentMacroEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCreditAgentMacro.match), switchMap(() => {
7
+ const url = `${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/macros/credit-agent`;
8
+ return zeniAPI.getJSON(url).pipe(mergeMap((response) => {
9
+ if (isSuccessResponse(response) && response.data != null) {
10
+ return from([
11
+ updateCreditAgentMacro(response.data),
12
+ fetchCreditAgentMacroSuccess(),
13
+ ]);
14
+ }
15
+ else {
16
+ return of(fetchCreditAgentMacroFailure(response.status));
17
+ }
18
+ }), catchError((error) => of(fetchCreditAgentMacroFailure(createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))))));
19
+ }));
@@ -0,0 +1,58 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { updateCreditAgentMacro } from '../../../entity/creditAgent/creditAgentReducer';
4
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
6
+ import { saveCreditAgentMacro, saveCreditAgentMacroFailure, saveCreditAgentMacroSuccess, } from '../creditAgentViewReducer';
7
+ export const saveCreditAgentMacroEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(saveCreditAgentMacro.match), switchMap((action) => {
8
+ const { instructions } = action.payload;
9
+ const existingMacro = state$.value.creditAgentEntityState.macro;
10
+ // Fail fast if macro has not been loaded yet — avoids overwriting server-side
11
+ // name/description fields with empty defaults.
12
+ if (existingMacro == null) {
13
+ return from([
14
+ saveCreditAgentMacroFailure(createZeniAPIStatus('Save failed', 'Cannot save macro: macro data has not been loaded yet.')),
15
+ openSnackbar({
16
+ messageSection: 'credit_agent_save_macro',
17
+ messageText: 'failed',
18
+ type: 'error',
19
+ }),
20
+ ]);
21
+ }
22
+ const url = `${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/macros/credit-agent`;
23
+ const body = {
24
+ instructions,
25
+ name: existingMacro.name,
26
+ description: existingMacro.description,
27
+ };
28
+ return zeniAPI.putAndGetJSON(url, body).pipe(mergeMap((response) => {
29
+ if (isSuccessResponse(response) && response.data != null) {
30
+ return from([
31
+ updateCreditAgentMacro(response.data),
32
+ saveCreditAgentMacroSuccess(),
33
+ openSnackbar({
34
+ messageSection: 'credit_agent_save_macro',
35
+ messageText: 'success',
36
+ type: 'success',
37
+ }),
38
+ ]);
39
+ }
40
+ else {
41
+ return from([
42
+ saveCreditAgentMacroFailure(response.status),
43
+ openSnackbar({
44
+ messageSection: 'credit_agent_save_macro',
45
+ messageText: 'failed',
46
+ type: 'error',
47
+ }),
48
+ ]);
49
+ }
50
+ }), catchError((error) => from([
51
+ saveCreditAgentMacroFailure(createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))),
52
+ openSnackbar({
53
+ messageSection: 'credit_agent_save_macro',
54
+ messageText: 'failed',
55
+ type: 'error',
56
+ }),
57
+ ])));
58
+ }));
@@ -0,0 +1,39 @@
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 { scheduleTenantCreditScoreCron, scheduleTenantCreditScoreCronFailure, scheduleTenantCreditScoreCronSuccess, } from '../creditAgentViewReducer';
6
+ export const scheduleTenantCreditScoreCronEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(scheduleTenantCreditScoreCron.match), mergeMap((action) => {
7
+ const { tenantId } = action.payload;
8
+ const url = `${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/crons/cards/tenant-credit-score`;
9
+ const body = tenantId != null ? { tenant_id: tenantId } : {};
10
+ return zeniAPI.postAndGetJSON(url, body).pipe(mergeMap((response) => {
11
+ if (isSuccessResponse(response)) {
12
+ return from([
13
+ scheduleTenantCreditScoreCronSuccess(tenantId),
14
+ openSnackbar({
15
+ messageSection: 'credit_agent_schedule_cron',
16
+ messageText: 'success',
17
+ type: 'success',
18
+ }),
19
+ ]);
20
+ }
21
+ else {
22
+ return from([
23
+ scheduleTenantCreditScoreCronFailure(tenantId, response.status),
24
+ openSnackbar({
25
+ messageSection: 'credit_agent_schedule_cron',
26
+ messageText: 'failed',
27
+ type: 'error',
28
+ }),
29
+ ]);
30
+ }
31
+ }), catchError((error) => from([
32
+ scheduleTenantCreditScoreCronFailure(tenantId, createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))),
33
+ openSnackbar({
34
+ messageSection: 'credit_agent_schedule_cron',
35
+ messageText: 'failed',
36
+ type: 'error',
37
+ }),
38
+ ])));
39
+ }));
@@ -0,0 +1,62 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { updateCreditAgentRow } from '../../../entity/creditAgent/creditAgentReducer';
4
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
6
+ import { updateCardProfile, updateCardProfileFailure, updateCardProfileSuccess, } from '../creditAgentViewReducer';
7
+ export const updateCardProfileEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(updateCardProfile.match), mergeMap((action) => {
8
+ const { tenantId, tenantEmailDomain, update } = action.payload;
9
+ const url = `${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/cockpit/card-tenant-profiles`;
10
+ const body = {
11
+ tenant_namespace: tenantEmailDomain,
12
+ };
13
+ if (update.cardStatus != null) {
14
+ body.card_status = update.cardStatus;
15
+ }
16
+ if (update.creditLimit != null) {
17
+ body.credit_limit = update.creditLimit;
18
+ }
19
+ if (update.updatedByName != null) {
20
+ body.updated_by_name = update.updatedByName;
21
+ }
22
+ if (update.reason != null && update.reason.trim() !== '') {
23
+ body.reason = update.reason.trim();
24
+ }
25
+ return zeniAPI
26
+ .putAndGetJSON(url, body)
27
+ .pipe(mergeMap((response) => {
28
+ if (isSuccessResponse(response) &&
29
+ response.data != null &&
30
+ response.data.profile != null) {
31
+ return from([
32
+ updateCreditAgentRow({
33
+ payload: response.data.profile,
34
+ tenantId,
35
+ }),
36
+ updateCardProfileSuccess(tenantId),
37
+ openSnackbar({
38
+ messageSection: 'credit_agent_update_profile',
39
+ messageText: 'success',
40
+ type: 'success',
41
+ }),
42
+ ]);
43
+ }
44
+ else {
45
+ return from([
46
+ updateCardProfileFailure(tenantId, response.status),
47
+ openSnackbar({
48
+ messageSection: 'credit_agent_update_profile',
49
+ messageText: 'failed',
50
+ type: 'error',
51
+ }),
52
+ ]);
53
+ }
54
+ }), catchError((error) => from([
55
+ updateCardProfileFailure(tenantId, createZeniAPIStatus('Unexpected error', 'REST API call errored out: ' + JSON.stringify(error))),
56
+ openSnackbar({
57
+ messageSection: 'credit_agent_update_profile',
58
+ messageText: 'failed',
59
+ type: 'error',
60
+ }),
61
+ ])));
62
+ }));
@@ -0,0 +1,38 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap, withLatestFrom, } from 'rxjs/operators';
3
+ import { updateProjects } from '../../entity/project/projectReducer';
4
+ import { getIsAccountingProjectsEnabled } from '../../entity/tenant/tenantSelector';
5
+ import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
6
+ import { fetchProjectList, updateProjectList, updateProjectListFailure, } from './projectListReducer';
7
+ const buildProjectListQuery = (isIncludeDeleted) => {
8
+ const query = {
9
+ is_deleted: isIncludeDeleted,
10
+ sort_by: 'project_name',
11
+ sort_order: 'asc',
12
+ is_full: true,
13
+ };
14
+ return `?query=${encodeURIComponent(JSON.stringify(query))}`;
15
+ };
16
+ export const fetchProjectListEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchProjectList.match), withLatestFrom(state$), switchMap(([action, state]) => {
17
+ if (!getIsAccountingProjectsEnabled(state)) {
18
+ return of(updateProjectList({
19
+ status: createZeniAPIStatus('Success', ''),
20
+ data: { projects: [] },
21
+ }));
22
+ }
23
+ const { isIncludeDeleted } = action.payload;
24
+ const queryParams = buildProjectListQuery(isIncludeDeleted);
25
+ return zeniAPI
26
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/projects${queryParams}`)
27
+ .pipe(mergeMap((response) => {
28
+ if (isSuccessResponse(response)) {
29
+ return of(updateProjects(response.data?.projects ?? []), updateProjectList(response));
30
+ }
31
+ else {
32
+ return of(updateProjectListFailure(response.status));
33
+ }
34
+ }), catchError((error) => {
35
+ return of(updateProjectListFailure(createZeniAPIStatus('Unexpected Error', 'Fetch Projects REST API call errored out' +
36
+ JSON.stringify(error))));
37
+ }));
38
+ }));
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialState = {
3
+ fetchState: 'Not-Started',
4
+ error: undefined,
5
+ projectIds: [],
6
+ hasValidState() {
7
+ return this.fetchState == 'Completed';
8
+ },
9
+ };
10
+ const projectList = createSlice({
11
+ name: 'projectList',
12
+ initialState,
13
+ reducers: {
14
+ fetchProjectList: {
15
+ reducer(draft) {
16
+ draft.fetchState = 'In-Progress';
17
+ draft.error = undefined;
18
+ },
19
+ prepare(isIncludeDeleted) {
20
+ return { payload: { isIncludeDeleted: isIncludeDeleted ?? false } };
21
+ },
22
+ },
23
+ updateProjectList(draft, action) {
24
+ draft.projectIds =
25
+ action.payload.data?.projects?.map((project) => project.zeni_project_id) ?? [];
26
+ draft.fetchState = 'Completed';
27
+ draft.error = undefined;
28
+ },
29
+ updateProjectListFailure(draft, action) {
30
+ draft.fetchState = 'Error';
31
+ draft.error = action.payload;
32
+ },
33
+ clearProjectList(draft) {
34
+ Object.assign(draft, initialState);
35
+ },
36
+ },
37
+ });
38
+ export const { fetchProjectList, updateProjectList, updateProjectListFailure, clearProjectList, } = projectList.actions;
39
+ export default projectList.reducer;
@@ -0,0 +1,9 @@
1
+ import { getProjectsByIds } from '../../entity/project/projectSelector';
2
+ export const getProjectList = (projectState, projectListState) => {
3
+ return {
4
+ projects: getProjectsByIds(projectState, projectListState.projectIds),
5
+ fetchState: projectListState.fetchState,
6
+ error: projectListState.error,
7
+ version: 0,
8
+ };
9
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -51,6 +51,7 @@ export const toTransactionUpdatesFromTransactionDetailLocalData = (transactionDe
51
51
  lineDescription: lineItem.lineDescription,
52
52
  class: lineItem.class,
53
53
  account: lineItem.account,
54
+ project: lineItem.project,
54
55
  recommendation: convertCOTRecommendationsToRegular(lineItem.recommendationsWithCOT),
55
56
  };
56
57
  if (line.type === 'journal_entry_transaction_line' ||
@@ -14,6 +14,7 @@ import { fetchClassList } from '../../classList/classListReducer';
14
14
  import { getInitializedTransactionVendorLocalData } from '../../commonVendorView/transactionVendorView/transactionVendorLocalDataHelper';
15
15
  import { updateTransactionVendorLocalData } from '../../commonVendorView/transactionVendorView/transactionVendorViewReducer';
16
16
  import { fetchOwnerList } from '../../ownerList/ownerListReducer';
17
+ import { fetchProjectList } from '../../projectList/projectListReducer';
17
18
  import { fetchTransactionDetail, initializeTransactionDetailLocalData, removeTransactionDetail, updateTransactionDetailFetchState, } from '../transactionDetailReducer';
18
19
  import { getAllLinkedTransactions, getTransactionDetailKey, } from '../transactionDetailState';
19
20
  export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchTransactionDetail.match), mergeMap((action) => {
@@ -39,6 +40,11 @@ export const fetchTransactionDetailEpic = (actions$, state$, zeniAPI) => actions
39
40
  classList.fetchState !== 'In-Progress') {
40
41
  transactionActions.push(fetchClassList());
41
42
  }
43
+ const projectList = state$.value.projectListState;
44
+ if (projectList.hasValidState() === false &&
45
+ projectList.fetchState !== 'In-Progress') {
46
+ transactionActions.push(fetchProjectList());
47
+ }
42
48
  transactionActions.push(updateTransactionDetailFetchState(transactionId, 'In-Progress'));
43
49
  const query = { transaction_type: transactionId.type };
44
50
  const getTransactionDetail$ = zeniAPI
@@ -181,6 +181,9 @@ const toTransactionUpdatePayload = (updates, detail, cotTransactionTracking, ven
181
181
  if (lineUpdates.account != null) {
182
182
  lineTobeUpdated.account = lineUpdates.account;
183
183
  }
184
+ if (lineUpdates.project != null) {
185
+ lineTobeUpdated.project = lineUpdates.project;
186
+ }
184
187
  if (lineUpdates.customer != null) {
185
188
  lineTobeUpdated.customer = lineUpdates.customer;
186
189
  }