@zeniai/client-epic-state 5.0.42 → 5.0.43-betaRD1

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 (118) hide show
  1. package/lib/commonStateTypes/recommendationBase.d.ts +1 -1
  2. package/lib/entity/chargeCardRepayment/chargeCardRepayment.d.ts +1 -1
  3. package/lib/entity/creditAgent/creditAgentPayload.d.ts +41 -0
  4. package/lib/entity/creditAgent/creditAgentPayload.js +40 -0
  5. package/lib/entity/creditAgent/creditAgentReducer.d.ts +9 -0
  6. package/lib/entity/creditAgent/creditAgentReducer.js +37 -0
  7. package/lib/entity/creditAgent/creditAgentSelector.d.ts +3 -0
  8. package/lib/entity/creditAgent/creditAgentSelector.js +10 -0
  9. package/lib/entity/creditAgent/creditAgentState.d.ts +39 -0
  10. package/lib/entity/creditAgent/creditAgentState.js +17 -0
  11. package/lib/entity/project/projectPayload.d.ts +7 -0
  12. package/lib/entity/project/projectPayload.js +15 -1
  13. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  14. package/lib/entity/snackbar/snackbarTypes.js +3 -0
  15. package/lib/entity/task/taskPayload.d.ts +1 -0
  16. package/lib/entity/task/taskPayload.js +5 -0
  17. package/lib/entity/task/taskState.d.ts +5 -0
  18. package/lib/entity/task/taskState.js +6 -1
  19. package/lib/entity/tenant/clearAllEpic.d.ts +6 -3
  20. package/lib/entity/tenant/clearAllEpic.js +8 -2
  21. package/lib/entity/transaction/payloadTypes/transactionLinePayload.d.ts +2 -0
  22. package/lib/entity/transaction/payloadTypes/transactionLinePayload.js +9 -0
  23. package/lib/entity/transaction/stateTypes/transactionLine.d.ts +2 -0
  24. package/lib/epic.d.ts +8 -1
  25. package/lib/epic.js +8 -1
  26. package/lib/esm/entity/creditAgent/creditAgentPayload.js +36 -0
  27. package/lib/esm/entity/creditAgent/creditAgentReducer.js +33 -0
  28. package/lib/esm/entity/creditAgent/creditAgentSelector.js +6 -0
  29. package/lib/esm/entity/creditAgent/creditAgentState.js +13 -0
  30. package/lib/esm/entity/project/projectPayload.js +12 -0
  31. package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
  32. package/lib/esm/entity/task/taskPayload.js +6 -1
  33. package/lib/esm/entity/task/taskState.js +3 -0
  34. package/lib/esm/entity/tenant/clearAllEpic.js +8 -2
  35. package/lib/esm/entity/transaction/payloadTypes/transactionLinePayload.js +9 -0
  36. package/lib/esm/epic.js +8 -1
  37. package/lib/esm/index.js +18 -10
  38. package/lib/esm/reducer.js +12 -3
  39. package/lib/esm/view/common/recurringViewHelper.js +17 -0
  40. package/lib/esm/view/creditAgentView/buildCreditReportCsv.js +44 -0
  41. package/lib/esm/view/creditAgentView/creditAgentViewPayload.js +2 -0
  42. package/lib/esm/view/creditAgentView/creditAgentViewReducer.js +183 -0
  43. package/lib/esm/view/creditAgentView/creditAgentViewSelector.js +85 -0
  44. package/lib/esm/view/creditAgentView/creditAgentViewState.js +20 -0
  45. package/lib/esm/view/creditAgentView/epics/fetchCardProfilesEpic.js +20 -0
  46. package/lib/esm/view/creditAgentView/epics/fetchCreditAgentAccessEpic.js +13 -0
  47. package/lib/esm/view/creditAgentView/epics/fetchCreditAgentMacroEpic.js +19 -0
  48. package/lib/esm/view/creditAgentView/epics/saveCreditAgentMacroEpic.js +58 -0
  49. package/lib/esm/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.js +39 -0
  50. package/lib/esm/view/creditAgentView/epics/updateCardProfileEpic.js +62 -0
  51. package/lib/esm/view/projectList/fetchProjectListEpic.js +38 -0
  52. package/lib/esm/view/projectList/projectListPayload.js +1 -0
  53. package/lib/esm/view/projectList/projectListReducer.js +39 -0
  54. package/lib/esm/view/projectList/projectListSelector.js +9 -0
  55. package/lib/esm/view/projectList/projectListState.js +1 -0
  56. package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +2 -0
  57. package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +5 -0
  58. package/lib/esm/view/taskManager/taskDetailView/taskDetail.js +1 -0
  59. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +5 -0
  60. package/lib/esm/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  61. package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  62. package/lib/esm/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -0
  63. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +14 -2
  64. package/lib/index.d.ts +24 -14
  65. package/lib/index.js +81 -46
  66. package/lib/reducer.d.ts +12 -3
  67. package/lib/reducer.js +12 -3
  68. package/lib/view/common/recurringViewHelper.d.ts +3 -2
  69. package/lib/view/common/recurringViewHelper.js +18 -1
  70. package/lib/view/creditAgentView/buildCreditReportCsv.d.ts +17 -0
  71. package/lib/view/creditAgentView/buildCreditReportCsv.js +47 -0
  72. package/lib/view/creditAgentView/creditAgentViewPayload.d.ts +9 -0
  73. package/lib/view/creditAgentView/creditAgentViewPayload.js +7 -0
  74. package/lib/view/creditAgentView/creditAgentViewReducer.d.ts +41 -0
  75. package/lib/view/creditAgentView/creditAgentViewReducer.js +187 -0
  76. package/lib/view/creditAgentView/creditAgentViewSelector.d.ts +20 -0
  77. package/lib/view/creditAgentView/creditAgentViewSelector.js +93 -0
  78. package/lib/view/creditAgentView/creditAgentViewState.d.ts +34 -0
  79. package/lib/view/creditAgentView/creditAgentViewState.js +22 -0
  80. package/lib/view/creditAgentView/epics/fetchCardProfilesEpic.d.ts +15 -0
  81. package/lib/view/creditAgentView/epics/fetchCardProfilesEpic.js +24 -0
  82. package/lib/view/creditAgentView/epics/fetchCreditAgentAccessEpic.d.ts +11 -0
  83. package/lib/view/creditAgentView/epics/fetchCreditAgentAccessEpic.js +17 -0
  84. package/lib/view/creditAgentView/epics/fetchCreditAgentMacroEpic.d.ts +15 -0
  85. package/lib/view/creditAgentView/epics/fetchCreditAgentMacroEpic.js +23 -0
  86. package/lib/view/creditAgentView/epics/saveCreditAgentMacroEpic.d.ts +29 -0
  87. package/lib/view/creditAgentView/epics/saveCreditAgentMacroEpic.js +62 -0
  88. package/lib/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.d.ts +30 -0
  89. package/lib/view/creditAgentView/epics/scheduleTenantCreditScoreCronEpic.js +43 -0
  90. package/lib/view/creditAgentView/epics/updateCardProfileEpic.d.ts +37 -0
  91. package/lib/view/creditAgentView/epics/updateCardProfileEpic.js +66 -0
  92. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  93. package/lib/view/projectList/fetchProjectListEpic.d.ts +8 -0
  94. package/lib/view/projectList/fetchProjectListEpic.js +42 -0
  95. package/lib/view/projectList/projectListPayload.d.ts +7 -0
  96. package/lib/view/projectList/projectListPayload.js +2 -0
  97. package/lib/view/projectList/projectListReducer.d.ts +9 -0
  98. package/lib/view/projectList/projectListReducer.js +43 -0
  99. package/lib/view/projectList/projectListSelector.d.ts +8 -0
  100. package/lib/view/projectList/projectListSelector.js +13 -0
  101. package/lib/view/projectList/projectListState.d.ts +4 -0
  102. package/lib/view/projectList/projectListState.js +2 -0
  103. package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +2 -0
  104. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +5 -0
  105. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +3 -1
  106. package/lib/view/taskManager/taskDetailView/taskDetail.js +1 -0
  107. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +1 -0
  108. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +5 -0
  109. package/lib/view/transactionDetail/epics/saveTransactionHelper.js +1 -0
  110. package/lib/view/transactionDetail/epics/transactionDetailEpic.d.ts +2 -1
  111. package/lib/view/transactionDetail/epics/transactionDetailEpic.js +6 -0
  112. package/lib/view/transactionDetail/epics/updateTransactionDetailEpic.js +3 -0
  113. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +3 -0
  114. package/lib/view/transactionDetail/transactionDetailSelector.js +13 -1
  115. package/lib/view/transactionDetail/transactionDetailState.d.ts +2 -0
  116. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +2 -0
  117. package/package.json +1 -1
  118. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -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 {};
@@ -12,12 +12,14 @@ export const initializeTaskToLocalStoreEpic = (actions$, state$) => actions$.pip
12
12
  description: task.description,
13
13
  status: task.status.code,
14
14
  assignee: task.assignees,
15
+ groupAssignees: task.groupAssignees,
15
16
  dueDate: task.dueDate,
16
17
  priority: task.priority.code,
17
18
  tagIds: task.tagIds,
18
19
  fileIds: task.fileIds,
19
20
  type: task.type,
20
21
  recurringFrequency: task.recurringFrequency,
22
+ recurringDaysOfWeek: task.recurringDaysOfWeek,
21
23
  recurringEndDateLocalData: {
22
24
  recurringDatePickerOptionsType: 'date', // by default, date would be selected
23
25
  recurringEndDate: task.recurringEndDate,
@@ -91,9 +91,14 @@ const prepareTaskPayload = (state, taskId, taskGroupId) => {
91
91
  recurring_start_date: localData.type.code === 'recurring'
92
92
  ? (localData.recurringStartDate?.format(DEFAULT_DATE_FORMAT) ?? null)
93
93
  : null,
94
+ recurring_days_of_week: localData.type.code === 'recurring' &&
95
+ localData.recurringFrequency === 'semi_weekly'
96
+ ? (localData.recurringDaysOfWeek ?? [])
97
+ : [],
94
98
  sync_token: syncToken,
95
99
  task_group_ids: taskGroupId != null ? [taskGroupId] : [],
96
100
  time_spent: convertHHMMStrToMinutes(localData.timeSpent),
101
+ group_assignees: localData.groupAssignees,
97
102
  ...(taskId == null ? { is_private: localData.isPrivate ?? false } : {}),
98
103
  };
99
104
  };
@@ -3,6 +3,7 @@ export const initialTaskDetailLocalData = {
3
3
  description: '',
4
4
  status: 'todo',
5
5
  assignee: [],
6
+ groupAssignees: [],
6
7
  dueDate: undefined,
7
8
  priority: 'medium',
8
9
  tagIds: [],
@@ -26,6 +26,7 @@ export const getTaskDetail = (state, taskId) => {
26
26
  let isDeleted = undefined;
27
27
  let recurringSourceTaskId = undefined;
28
28
  let snoozedUntil = undefined;
29
+ let taskGroupId = undefined;
29
30
  if (taskId != null && sourceTaskDetail != null) {
30
31
  const taskEntity = getTaskById(taskState, taskId);
31
32
  const fileIdsInEntity = taskEntity?.fileIds ?? [];
@@ -35,6 +36,7 @@ export const getTaskDetail = (state, taskId) => {
35
36
  isDeleted = taskEntity.isDeleted;
36
37
  recurringSourceTaskId = taskEntity.recurringSourceTaskId;
37
38
  snoozedUntil = taskEntity.snoozedUntil;
39
+ taskGroupId = taskEntity.taskGroupIds[0];
38
40
  }
39
41
  if (fileIdsInEntity.length > 0) {
40
42
  fetchStatus = reduceFetchState([
@@ -87,6 +89,7 @@ export const getTaskDetail = (state, taskId) => {
87
89
  recurringSourceTaskId,
88
90
  showTaskDetailFormFooter,
89
91
  snoozedUntil,
92
+ taskGroupId,
90
93
  };
91
94
  };
92
95
  export const allTaskStatus = [
@@ -140,11 +143,13 @@ const showFormFooter = (taskDetailLocalData, taskDetailInStore) => {
140
143
  taskDetailLocalData.status !== taskDetailInStore.status.code ||
141
144
  !isEqual(taskDetailInStore.tagIds, taskDetailLocalData.tagIds) ||
142
145
  !isEqual(taskDetailLocalData.assignee, taskDetailInStore?.assignees ?? []) ||
146
+ !isEqual(taskDetailLocalData.groupAssignees, taskDetailInStore?.groupAssignees ?? []) ||
143
147
  !isEqual(taskDetailLocalData.fileIds, taskDetailInStore.fileIds ?? []) ||
144
148
  !isEqual(taskDetailLocalData.dueDate, taskDetailInStore.dueDate) ||
145
149
  !isEqual(taskDetailLocalData.type, taskDetailInStore.type) ||
146
150
  !isEqual(taskDetailLocalData.savedRecurringEndDate, taskDetailInStore.recurringEndDate) ||
147
151
  !isEqual(taskDetailLocalData.recurringFrequency, taskDetailInStore.recurringFrequency) ||
152
+ !isEqual(taskDetailLocalData.recurringDaysOfWeek, taskDetailInStore.recurringDaysOfWeek) ||
148
153
  !isEqual(taskDetailLocalData.recurringStartDate, taskDetailInStore.recurringStartDate) ||
149
154
  !isEqual(taskDetailLocalData.timeSpent, taskDetailInStore.timeSpent)) {
150
155
  return true;
@@ -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
  }
@@ -1,6 +1,6 @@
1
1
  import recordGet from 'lodash/get';
2
2
  import { reduceFetchState } from '../../commonStateTypes/reduceFetchState';
3
- import { getIsAccountingClassesEnabled } from '../../entity/tenant/tenantSelector';
3
+ import { getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, } from '../../entity/tenant/tenantSelector';
4
4
  import { toTransactionTypeStrict } from '../../entity/transaction/stateTypes/transactionType';
5
5
  import { getTransactionWithCOT } from '../../entity/transaction/transactionHelper';
6
6
  import { getSupportedTransactionById } from '../../entity/transaction/transactionSelector';
@@ -8,9 +8,10 @@ import { getVendorsByVendorIds } from '../../entity/vendor/vendorSelector';
8
8
  import { dateNow } from '../../zeniDayJS';
9
9
  import { getAccountList, getNestedAccountListHierarchy, } from '../accountList/accountListSelector';
10
10
  import { getClassList, getNestedClassListHierarchy, } from '../classList/classListSelector';
11
+ import { getProjectList, } from '../projectList/projectListSelector';
11
12
  import { getAllLinkedTransactions, getTransactionDetailKey, initialSupportedTransactionDetail, } from './transactionDetailState';
12
13
  export const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = true) => {
13
- const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, } = state;
14
+ const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, projectState, projectListState, } = state;
14
15
  const detailKey = getTransactionDetailKey(transactionId);
15
16
  const transactionDetail = recordGet(transactionDetailState.transactionDetailById, detailKey);
16
17
  let fetchState = {
@@ -56,6 +57,15 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
56
57
  const classList = isAccountingClassesEnabled
57
58
  ? getClassList(classState, classListState)
58
59
  : { classes: [], nestedClassHierarchy: [], fetchState: 'Completed', error: undefined, version: 0 };
60
+ const isAccountingProjectsEnabled = getIsAccountingProjectsEnabled(state);
61
+ const projectList = isAccountingProjectsEnabled
62
+ ? getProjectList(projectState, projectListState)
63
+ : {
64
+ projects: [],
65
+ fetchState: 'Completed',
66
+ error: undefined,
67
+ version: 0,
68
+ };
59
69
  const accountsHierarchyList = getNestedAccountListHierarchy(accountListState, 'accountList');
60
70
  const classHierarchyList = isAccountingClassesEnabled
61
71
  ? getNestedClassListHierarchy(classListState)
@@ -78,6 +88,8 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
78
88
  accountsHierarchyList,
79
89
  classList: classList,
80
90
  isAccountingClassesEnabled,
91
+ isAccountingProjectsEnabled,
92
+ projectList,
81
93
  isUpdateNotAllowed: transactionDetail?.isUpdateNotAllowed,
82
94
  transactionDetailLocalData: transactionDetail?.transactionDetailLocalData ??
83
95
  initialSupportedTransactionDetail.transactionDetailLocalData,