@zeniai/client-epic-state 5.0.95-betaAK1 → 5.0.95-betaML1

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 (85) hide show
  1. package/lib/commonStateTypes/amount.d.ts +0 -1
  2. package/lib/commonStateTypes/amount.js +1 -9
  3. package/lib/commonStateTypes/workingDayHelper.d.ts +0 -9
  4. package/lib/commonStateTypes/workingDayHelper.js +1 -28
  5. package/lib/entity/tenant/clearAllEpic.d.ts +1 -3
  6. package/lib/entity/tenant/clearAllEpic.js +0 -4
  7. package/lib/epic.d.ts +1 -7
  8. package/lib/epic.js +1 -7
  9. package/lib/esm/commonStateTypes/amount.js +0 -7
  10. package/lib/esm/commonStateTypes/workingDayHelper.js +0 -26
  11. package/lib/esm/entity/tenant/clearAllEpic.js +0 -4
  12. package/lib/esm/epic.js +1 -7
  13. package/lib/esm/index.js +4 -9
  14. package/lib/esm/reducer.js +0 -6
  15. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +15 -0
  16. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +63 -5
  17. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +12 -3
  18. package/lib/esm/view/recommendation/recommendationReducer.js +18 -1
  19. package/lib/esm/view/recommendation/recommendationStaleResponseHelper.js +26 -0
  20. package/lib/esm/view/spendManagement/autotransferRules/autoTransferRulesSelector.js +2 -22
  21. package/lib/esm/view/transactionDetail/epics/initializeTransactionDetailLocalDataEpic.js +7 -0
  22. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +44 -3
  23. package/lib/index.d.ts +5 -14
  24. package/lib/index.js +4 -23
  25. package/lib/reducer.d.ts +0 -6
  26. package/lib/reducer.js +0 -6
  27. package/lib/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.d.ts +2 -1
  28. package/lib/view/expenseAutomationView/epics/transactionCategorization/initializeTransactionCategorizationLocalDataEpic.js +15 -0
  29. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +63 -5
  30. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +2 -2
  31. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +10 -1
  32. package/lib/view/recommendation/recommendationReducer.d.ts +3 -1
  33. package/lib/view/recommendation/recommendationReducer.js +19 -2
  34. package/lib/view/recommendation/recommendationStaleResponseHelper.d.ts +7 -0
  35. package/lib/view/recommendation/recommendationStaleResponseHelper.js +30 -0
  36. package/lib/view/spendManagement/autotransferRules/autoTransferRulesSelector.d.ts +1 -8
  37. package/lib/view/spendManagement/autotransferRules/autoTransferRulesSelector.js +1 -21
  38. package/lib/view/spendManagement/autotransferRules/autoTransferRulesState.d.ts +0 -22
  39. package/lib/view/transactionDetail/epics/initializeTransactionDetailLocalDataEpic.d.ts +2 -1
  40. package/lib/view/transactionDetail/epics/initializeTransactionDetailLocalDataEpic.js +7 -0
  41. package/lib/view/transactionDetail/transactionDetailReducer.js +44 -3
  42. package/lib/zeniAPI.d.ts +0 -1
  43. package/package.json +1 -1
  44. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowPayload.js +0 -29
  45. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowReducer.js +0 -78
  46. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowSelector.js +0 -47
  47. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowState.js +0 -47
  48. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/epics/fetchCashManagementSettingsEpic.js +0 -34
  49. package/lib/esm/view/spendManagement/cashManagement/autoSweepFlow/epics/saveAutoSweepSettingsEpic.js +0 -32
  50. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewPayload.js +0 -54
  51. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewReducer.js +0 -92
  52. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewSelector.js +0 -225
  53. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewState.js +0 -10
  54. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementBannerEpic.js +0 -23
  55. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementOverviewPageEpic.js +0 -36
  56. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementRecommendationEpic.js +0 -27
  57. package/lib/esm/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchRecentTransferEpic.js +0 -28
  58. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowPayload.d.ts +0 -47
  59. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowPayload.js +0 -34
  60. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowReducer.d.ts +0 -23
  61. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowReducer.js +0 -82
  62. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowSelector.d.ts +0 -40
  63. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowSelector.js +0 -51
  64. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowState.d.ts +0 -37
  65. package/lib/view/spendManagement/cashManagement/autoSweepFlow/autoSweepFlowState.js +0 -53
  66. package/lib/view/spendManagement/cashManagement/autoSweepFlow/epics/fetchCashManagementSettingsEpic.d.ts +0 -14
  67. package/lib/view/spendManagement/cashManagement/autoSweepFlow/epics/fetchCashManagementSettingsEpic.js +0 -38
  68. package/lib/view/spendManagement/cashManagement/autoSweepFlow/epics/saveAutoSweepSettingsEpic.d.ts +0 -7
  69. package/lib/view/spendManagement/cashManagement/autoSweepFlow/epics/saveAutoSweepSettingsEpic.js +0 -36
  70. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewPayload.d.ts +0 -56
  71. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewPayload.js +0 -60
  72. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewReducer.d.ts +0 -22
  73. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewReducer.js +0 -96
  74. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewSelector.d.ts +0 -59
  75. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewSelector.js +0 -230
  76. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewState.d.ts +0 -122
  77. package/lib/view/spendManagement/cashManagement/cashManagementOverview/cashManagementOverviewState.js +0 -13
  78. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementBannerEpic.d.ts +0 -7
  79. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementBannerEpic.js +0 -27
  80. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementOverviewPageEpic.d.ts +0 -9
  81. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementOverviewPageEpic.js +0 -40
  82. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementRecommendationEpic.d.ts +0 -7
  83. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchCashManagementRecommendationEpic.js +0 -31
  84. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchRecentTransferEpic.d.ts +0 -15
  85. package/lib/view/spendManagement/cashManagement/cashManagementOverview/epics/fetchRecentTransferEpic.js +0 -32
@@ -1,10 +1,6 @@
1
- import { Amount } from '../../../commonStateTypes/amount';
2
1
  import { FetchStateAndError, FetchedState, ID } from '../../../commonStateTypes/common';
3
2
  import { ZeniDate } from '../../../zeniDayJS';
4
- import { AutoSweepFrequency } from '../cashManagement/autoSweepFlow/autoSweepFlowState';
5
- import { FundingAccount } from '../commonSetup/setupViewSelector';
6
3
  import { CommonHistoryView } from '../commonHistoryView/commonHistory';
7
- import { TreasurySummaryWithBalance } from '../treasury/treasuryList/treasuryDetailState';
8
4
  import { ReviewTransferDetail } from '../zeniAccounts/transferDetail/transferDetailState';
9
5
  import { AutoTransferRuleFrequency, AutoTransferRuleLocalData, AutoTransferRuleType } from './autoTransferRulesPayload';
10
6
  export interface AutoTransferRule {
@@ -31,24 +27,6 @@ export interface DestinationBankAccountMetadata {
31
27
  accountType: string;
32
28
  percentage: number;
33
29
  }
34
- /**
35
- * Render-ready view of the user's auto-sweep cash-management config,
36
- * surfaced alongside `AutoTransferRule[]` in `AutoTransferRulesSelectorView`.
37
- * Kept as a distinct shape (not folded into `AutoTransferRule`) so the rules
38
- * list can special-case its rendering without polluting the rule type union.
39
- *
40
- * Present only when `autoSweepFlowState.settingsId` is set — i.e. the user
41
- * has saved their auto-sweep settings at least once.
42
- */
43
- export interface CashManagementRule {
44
- bufferAmount: Amount;
45
- frequency: AutoSweepFrequency;
46
- memo: string;
47
- settingsId: ID;
48
- nextTransferDate?: ZeniDate;
49
- primaryFundingAccount?: FundingAccount;
50
- treasurySummary?: TreasurySummaryWithBalance;
51
- }
52
30
  export interface AutoTransferRulesState extends FetchedState {
53
31
  autoTransferReviewDetail: ReviewTransferDetail;
54
32
  createRuleFetchState: FetchStateAndError;
@@ -1,5 +1,6 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { RootState } from '../../../reducer';
3
+ import { cancelEntityRecommendationsForLineUpdate } from '../../recommendation/recommendationReducer';
3
4
  import { clearTransactionDetailLocalData, initializeTransactionDetailLocalData, saveTransactionDetailLocalData } from '../transactionDetailReducer';
4
- export type ActionType = ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof saveTransactionDetailLocalData> | ReturnType<typeof clearTransactionDetailLocalData>;
5
+ export type ActionType = ReturnType<typeof initializeTransactionDetailLocalData> | ReturnType<typeof saveTransactionDetailLocalData> | ReturnType<typeof clearTransactionDetailLocalData> | ReturnType<typeof cancelEntityRecommendationsForLineUpdate>;
5
6
  export declare const initializeTransactionDetailLocalDataEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => import("rxjs").Observable<ActionType>;
@@ -5,6 +5,7 @@ const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
7
7
  const accountListSelector_1 = require("../../accountList/accountListSelector");
8
+ const recommendationReducer_1 = require("../../recommendation/recommendationReducer");
8
9
  const transactionDetailLocalDataHelper_1 = require("../transactionDetailLocalDataHelper");
9
10
  const transactionDetailReducer_1 = require("../transactionDetailReducer");
10
11
  const transactionDetailState_1 = require("../transactionDetailState");
@@ -17,6 +18,12 @@ const initializeTransactionDetailLocalDataEpic = (actions$, state$) => actions$.
17
18
  if (detail != null) {
18
19
  const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(state$.value.accountState, state$.value.accountListState, 'accountList');
19
20
  const localData = (0, transactionDetailLocalDataHelper_1.toTransactionDetailLocalData)(detail, vendorId, uncategorizedIncomeExpense);
21
+ // Cancel any in-flight line-update recommendations fetch for
22
+ // this transaction BEFORE the clear+restore writes land. The
23
+ // shared epic's takeUntil observes this action and unsubscribes
24
+ // the HTTP stream, preventing a stale response from being
25
+ // applied to the freshly-restored local data.
26
+ fetchActions.push((0, recommendationReducer_1.cancelEntityRecommendationsForLineUpdate)(transactionId));
20
27
  fetchActions.push((0, transactionDetailReducer_1.clearTransactionDetailLocalData)({ transactionId }));
21
28
  fetchActions.push((0, transactionDetailReducer_1.saveTransactionDetailLocalData)({
22
29
  transactionId,
@@ -8,6 +8,9 @@ exports.setIsVendorUpdateAllChecked = exports.updateVendorBulkRecommendationsFet
8
8
  const toolkit_1 = require("@reduxjs/toolkit");
9
9
  const get_1 = __importDefault(require("lodash/get"));
10
10
  const entity_1 = require("../../entity/genericEntity/entity");
11
+ const customerTransaction_1 = require("../../entity/transaction/stateTypes/customerTransaction");
12
+ const vendorTransaction_1 = require("../../entity/transaction/stateTypes/vendorTransaction");
13
+ const recommendationStaleResponseHelper_1 = require("../recommendation/recommendationStaleResponseHelper");
11
14
  const transactionDetailLocalDataHelper_1 = require("./transactionDetailLocalDataHelper");
12
15
  const transactionDetailState_1 = require("./transactionDetailState");
13
16
  exports.initialState = {
@@ -258,6 +261,17 @@ const transactionDetail = (0, toolkit_1.createSlice)({
258
261
  // captures the snapshot before the epic's start arm runs and would
259
262
  // otherwise clobber In-Progress back to undefined). Treat the field as
260
263
  // sticky: only let the caller override it when they explicitly set it.
264
+ //
265
+ // Note on Cancel: the explicit user-Cancel path NO LONGER relies on
266
+ // this stickiness to release In-Progress lines. Cancel dispatches
267
+ // `cancelEntityRecommendationsForLineUpdate` ahead of the
268
+ // clear+save pair (see initializeTransactionDetailLocalDataEpic);
269
+ // the shared line-update epic's `takeUntil` catches that action
270
+ // and unsubscribes the HTTP stream, so no markCompleted /
271
+ // setEntityRecommendation arm fires for the cancelled fetch.
272
+ // Stickiness still matters for the BENIGN snapshot-rebuild paths
273
+ // described above where a fetch is legitimately in flight and
274
+ // must keep its skeleton until the success/failure arm lands.
261
275
  const mergedLineItemById = {};
262
276
  Object.entries(incoming.lineItemById ?? {}).forEach(([lineId, line]) => {
263
277
  mergedLineItemById[lineId] = {
@@ -393,10 +407,37 @@ const transactionDetail = (0, toolkit_1.createSlice)({
393
407
  const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
394
408
  const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
395
409
  if (detail != null) {
396
- const newLocalData = (0, transactionDetailLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(transaction, detail.transactionDetailLocalData, action.payload.entity, lineIds, uncategorizedIncomeExpense, recommendationWithCOTByLineId);
410
+ // Stale-response guard. If the user has changed their selection
411
+ // (or Cancel restored an earlier vendor) between the fetch
412
+ // starting and the response landing, the payload entity will
413
+ // no longer match what's currently selected on the line(s).
414
+ // Apply recommendations only to the still-matching subset of
415
+ // lines. Lines that fail the guard still flip to Completed
416
+ // below so their inline skeletons resolve. This complements
417
+ // the epic-level `takeUntil`: even if a response slips
418
+ // through, it can't write recommendations onto unrelated
419
+ // selections.
420
+ //
421
+ // Detail flow: vendor + customer use page-level
422
+ // `selectedEntity`; JE / deposit use per-line `lineEntity`.
423
+ // Match the same dichotomy used by
424
+ // `setEntityRecommendationForLineIdInLocalData`'s
425
+ // `checkIfNotJEAndDeposit` test below.
426
+ const usesPageLevelEntity = (0, vendorTransaction_1.isVendorTransaction)(transaction) === true ||
427
+ (0, customerTransaction_1.isCustomerTransaction)(transaction) === true;
428
+ const matchedLineIds = (0, recommendationStaleResponseHelper_1.getLineIdsWhereEntityStillMatches)({
429
+ lineIds,
430
+ payloadEntity: action.payload.entity,
431
+ getCurrentEntityForLine: (lineId) => usesPageLevelEntity
432
+ ? detail.transactionDetailLocalData.selectedEntity
433
+ : detail.transactionDetailLocalData.lineItemById[lineId]
434
+ ?.lineEntity,
435
+ });
436
+ const newLocalData = (0, transactionDetailLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(transaction, detail.transactionDetailLocalData, action.payload.entity, matchedLineIds, uncategorizedIncomeExpense, recommendationWithCOTByLineId);
397
437
  // Release the per-line fetch flag for every line this fetch
398
- // covered so the inline skeleton resolves and the page-level
399
- // Save button can re-enable.
438
+ // covered (matched AND unmatched) so the inline skeleton
439
+ // resolves and the page-level Save button can re-enable.
440
+ // Unmatched lines are released without recommendation writes.
400
441
  lineIds.forEach((lineId) => {
401
442
  const lineItem = newLocalData.lineItemById[lineId];
402
443
  if (lineItem != null) {
package/lib/zeniAPI.d.ts CHANGED
@@ -10,7 +10,6 @@ export interface RESTAPIEndpoints {
10
10
  readonly authMicroServiceBaseUrl: string;
11
11
  readonly bankingMicroServiceBaseUrl: string;
12
12
  readonly cardMicroServiceBaseUrl: string;
13
- readonly cashManagementAgentBaseUrl: string;
14
13
  readonly communicationAgentMicroServiceBaseUrl: string;
15
14
  readonly documentAIMicroServiceBaseUrl: string;
16
15
  readonly fileMicroServiceBaseUrl: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.0.95-betaAK1",
3
+ "version": "5.0.95-betaML1",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -1,29 +0,0 @@
1
- import { toAmount } from '../../../../commonStateTypes/amount';
2
- import { date } from '../../../../zeniDayJS';
3
- import { toAutoSweepFrequency, } from './autoSweepFlowState';
4
- export const toSaveAutoSweepSettingsBody = (state) => ({
5
- frequency: state.frequency,
6
- memo: state.memo,
7
- minimum_buffer_usd: state.bufferAmount.amount,
8
- });
9
- /**
10
- * Map a `GET /cash-management/settings` payload into the slice's writable
11
- * fields. Defensive on the frequency (string-from-the-wire → union via
12
- * `toAutoSweepFrequency`, falling back to `'weekly'` if the server returns
13
- * something we don't model yet). Only the source account *id* is stored
14
- * here — the full deposit-account payload is published to the entity bucket
15
- * by the fetch epic.
16
- */
17
- export const toAutoSweepFlowStatePatch = (payload) => {
18
- const currencyCode = payload.source_bank_account.balances?.currency_code;
19
- const currencySymbol = payload.source_bank_account.balances?.currency_symbol;
20
- return {
21
- bufferAmount: toAmount(payload.minimum_buffer_usd, currencyCode ?? 'USD', currencySymbol ?? '$'),
22
- frequency: toAutoSweepFrequency(payload.frequency) ?? 'weekly',
23
- nextTransferDate: payload.next_transfer_date != null && payload.next_transfer_date !== ''
24
- ? date(payload.next_transfer_date)
25
- : undefined,
26
- primaryFundingAccountId: payload.source_bank_account.deposit_account_id ?? undefined,
27
- settingsId: payload.cash_management_settings_id ?? undefined,
28
- };
29
- };
@@ -1,78 +0,0 @@
1
- import { createSlice } from '@reduxjs/toolkit';
2
- import { toAutoSweepFlowStatePatch, } from './autoSweepFlowPayload';
3
- import { initialAutoSweepFlowState, } from './autoSweepFlowState';
4
- export const initialState = initialAutoSweepFlowState;
5
- const autoSweepFlow = createSlice({
6
- name: 'autoSweepFlow',
7
- initialState,
8
- reducers: {
9
- /**
10
- * Kicks off `GET /cash-management/settings`. Flips the top-level
11
- * fetchState to `In-Progress`; the fetch epic picks this up.
12
- */
13
- fetchCashManagementSettings(draft) {
14
- draft.fetchState = 'In-Progress';
15
- draft.error = undefined;
16
- },
17
- /**
18
- * Hydrates the form fields with the server-side settings (and stashes
19
- * the settings id for subsequent saves). Marks the GET as `Completed`.
20
- */
21
- updateCashManagementSettings(draft, action) {
22
- const patch = toAutoSweepFlowStatePatch(action.payload.data);
23
- draft.bufferAmount = patch.bufferAmount;
24
- draft.frequency = patch.frequency;
25
- draft.nextTransferDate = patch.nextTransferDate;
26
- draft.primaryFundingAccountId = patch.primaryFundingAccountId;
27
- draft.settingsId = patch.settingsId;
28
- draft.fetchState = 'Completed';
29
- draft.error = undefined;
30
- },
31
- updateCashManagementSettingsFetchStatus(draft, action) {
32
- draft.fetchState = action.payload.fetchState;
33
- draft.error = action.payload.error;
34
- },
35
- /**
36
- * Live-update the buffer (risk band) as the user toggles the risk picker
37
- * on the setup page, without staging frequency/memo. The selector derives
38
- * the risk-adjusted sweep amount off `bufferAmount`, so dispatching this on
39
- * every risk change keeps the setup and review screens in sync.
40
- */
41
- updateAutoSweepRisk(draft, action) {
42
- draft.bufferAmount = action.payload.bufferAmount;
43
- },
44
- /**
45
- * Stage the in-flight form values without submitting them — fired from
46
- * the setup→review transition so other selectors (and devtools) can see
47
- * what the user is about to confirm. Leaves `saveStatus` untouched; the
48
- * actual PUT only kicks off when the user clicks "Confirm Sweep" via
49
- * `saveAutoSweepSettings`.
50
- */
51
- updateAutoSweepDraft(draft, action) {
52
- draft.bufferAmount = action.payload.bufferAmount;
53
- draft.frequency = action.payload.frequency;
54
- draft.memo = action.payload.memo;
55
- },
56
- /**
57
- * Trigger the PUT for the auto-sweep settings already staged via
58
- * `updateAutoSweepDraft`. Carries no payload — flips `saveStatus` to
59
- * `In-Progress` and the save epic reads `bufferAmount` / `frequency` /
60
- * `memo` straight from the slice. Callers must ensure those fields
61
- * reflect the user's latest input before dispatching.
62
- */
63
- saveAutoSweepSettings(draft) {
64
- draft.saveStatus = { fetchState: 'In-Progress', error: undefined };
65
- },
66
- updateAutoSweepSettingsFetchStatus(draft, action) {
67
- draft.saveStatus = {
68
- fetchState: action.payload.fetchState,
69
- error: action.payload.error,
70
- };
71
- },
72
- clearAutoSweepFlow() {
73
- return initialAutoSweepFlowState;
74
- },
75
- },
76
- });
77
- export const { fetchCashManagementSettings, updateCashManagementSettings, updateCashManagementSettingsFetchStatus, updateAutoSweepRisk, updateAutoSweepDraft, saveAutoSweepSettings, updateAutoSweepSettingsFetchStatus, clearAutoSweepFlow, } = autoSweepFlow.actions;
78
- export default autoSweepFlow.reducer;
@@ -1,47 +0,0 @@
1
- import { getDepositAccountByDepositAccountId } from '../../../../entity/depositAccount/depositAccountSelector';
2
- import { mapDepositAccToFundingAccount, } from '../../commonSetup/setupViewSelector';
3
- import { getTreasuryDetail } from '../../treasury/treasuryList/treasuryDetailSelector';
4
- import { getCashManagementOverviewBanner } from '../cashManagementOverview/cashManagementOverviewSelector';
5
- import { RISK_BUFFER_AMOUNT, bufferAmountToRisk, } from './autoSweepFlowState';
6
- /**
7
- * Risk band the agent's recommended sweep amount is computed against. The
8
- * `sweepAmount` returned by the banner assumes this buffer, so the selector
9
- * adjusts the displayed sweep by the delta between the user's selected band
10
- * and this default.
11
- */
12
- const DEFAULT_RISK_LEVEL = 'moderate';
13
- export const getAutoSweepFlow = (state) => {
14
- const { bufferAmount, frequency, memo, saveStatus, settingsId, primaryFundingAccountId, fetchState, error, } = state.autoSweepFlowState;
15
- const depositAccount = primaryFundingAccountId != null
16
- ? getDepositAccountByDepositAccountId(state.depositAccountState, primaryFundingAccountId)
17
- : undefined;
18
- const risk = bufferAmountToRisk(bufferAmount.amount);
19
- // The banner's recommended sweep assumes the default buffer band; shift it
20
- // by the delta between the user's selected band and that default so a
21
- // tighter buffer sweeps more and a looser buffer sweeps less.
22
- const baseSweepAmount = getCashManagementOverviewBanner(state).amount;
23
- const sweepAmount = {
24
- ...baseSweepAmount,
25
- amount: baseSweepAmount.amount +
26
- RISK_BUFFER_AMOUNT[risk] -
27
- RISK_BUFFER_AMOUNT[DEFAULT_RISK_LEVEL],
28
- };
29
- return {
30
- fetchState,
31
- error,
32
- formData: {
33
- bufferAmount,
34
- frequency,
35
- memo,
36
- risk,
37
- },
38
- primaryFundingAccount: depositAccount != null
39
- ? mapDepositAccToFundingAccount(depositAccount)
40
- : undefined,
41
- saveStatus,
42
- settingsId,
43
- sweepAmount,
44
- treasurySummary: getTreasuryDetail(state).accountSummary,
45
- version: 0,
46
- };
47
- };
@@ -1,47 +0,0 @@
1
- import { toAmount } from '../../../../commonStateTypes/amount';
2
- import { stringToUnion } from '../../../../commonStateTypes/stringToUnion';
3
- /**
4
- * Cadence at which the auto-sweep transfer fires. Lowercase to match the
5
- * cash-management settings API contract (and the `SweepFrequency` literal
6
- * already used by `<AutoSweepSetupPage>` in web-components).
7
- */
8
- export const ALL_AUTO_SWEEP_FREQUENCIES = [
9
- 'daily',
10
- 'weekly',
11
- 'biweekly',
12
- 'monthly',
13
- ];
14
- export const toAutoSweepFrequency = (v) => stringToUnion(v ?? '', ALL_AUTO_SWEEP_FREQUENCIES);
15
- /**
16
- * Risk presets the auto-sweep setup form exposes. Each level maps to a
17
- * canonical minimum-buffer amount (USD). Selecting a level in the UI is
18
- * shorthand for choosing that buffer.
19
- */
20
- export const ALL_AUTO_SWEEP_RISK_LEVELS = ['low', 'moderate', 'high'];
21
- export const toAutoSweepRiskLevel = (v) => stringToUnion(v ?? '', ALL_AUTO_SWEEP_RISK_LEVELS);
22
- export const RISK_BUFFER_AMOUNT = {
23
- low: 15000,
24
- moderate: 10000,
25
- high: 5000,
26
- };
27
- /**
28
- * Maps a buffer amount back onto the closest preset risk level. Falls back
29
- * to `'moderate'` when the amount doesn't match a known preset (e.g. the
30
- * server returned a custom value). The dropdown in `<AutoSweepSetupPage>`
31
- * uses this so it can pre-select the user's existing band on edit.
32
- */
33
- export const bufferAmountToRisk = (amount) => {
34
- const match = Object.entries(RISK_BUFFER_AMOUNT).find(([, presetAmount]) => presetAmount === amount);
35
- return match != null ? match[0] : 'moderate';
36
- };
37
- export const initialAutoSweepFlowState = {
38
- bufferAmount: toAmount(10000, 'USD', '$'),
39
- frequency: 'weekly',
40
- memo: '',
41
- saveStatus: { fetchState: 'Not-Started', error: undefined },
42
- nextTransferDate: undefined,
43
- primaryFundingAccountId: undefined,
44
- settingsId: undefined,
45
- fetchState: 'Not-Started',
46
- error: undefined,
47
- };
@@ -1,34 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
- import { updateDepositAccounts } from '../../../../../entity/depositAccount/depositAccountReducer';
4
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
5
- import { fetchCashManagementSettings, updateCashManagementSettings, updateCashManagementSettingsFetchStatus, } from '../autoSweepFlowReducer';
6
- /**
7
- * Hits `GET /cash-management/settings` and hydrates the auto-sweep slice
8
- * with the server's existing settings (frequency, minimum buffer, settings
9
- * id). Called from the cash management overview page-fetch epic alongside
10
- * the other top-level fetches.
11
- */
12
- export const fetchCashManagementSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCashManagementSettings.match), switchMap(() => {
13
- const endpoint = `${zeniAPI.apiEndPoints.cashManagementAgentBaseUrl}/1.0/cash-management/settings`;
14
- return zeniAPI
15
- .getJSON(endpoint)
16
- .pipe(mergeMap((response) => {
17
- if (isSuccessResponse(response) && response.data != null) {
18
- return of(
19
- // Publish the source deposit account into the shared entity
20
- // bucket so the selector can hydrate the full `FundingAccount`
21
- // from `getDepositAccountByDepositAccountId` rather than the
22
- // auto-sweep slice holding a duplicate copy.
23
- updateDepositAccounts([response.data.source_bank_account]), updateCashManagementSettings({ data: response.data }));
24
- }
25
- return of(updateCashManagementSettingsFetchStatus({
26
- fetchState: 'Error',
27
- error: response.status,
28
- }));
29
- }), catchError((error) => of(updateCashManagementSettingsFetchStatus({
30
- fetchState: 'Error',
31
- error: createZeniAPIStatus('Unexpected Error', 'Fetch cash management settings REST API call errored out: ' +
32
- (error?.message ?? String(error))),
33
- }))));
34
- }));
@@ -1,32 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../../../responsePayload';
4
- import { toSaveAutoSweepSettingsBody, } from '../autoSweepFlowPayload';
5
- import { saveAutoSweepSettings, updateAutoSweepSettingsFetchStatus, } from '../autoSweepFlowReducer';
6
- export const saveAutoSweepSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(saveAutoSweepSettings.match), switchMap(() => {
7
- const endpoint = `${zeniAPI.apiEndPoints.cashManagementAgentBaseUrl}/1.0/cash-management/settings`;
8
- const { bufferAmount, frequency, memo, settingsId } = state$.value.autoSweepFlowState;
9
- const payload = toSaveAutoSweepSettingsBody({
10
- bufferAmount,
11
- frequency,
12
- memo,
13
- });
14
- // First-time setup (no settings id from the GET yet) → POST a new
15
- // record. Subsequent edits update the existing one via PUT.
16
- const request$ = settingsId == null
17
- ? zeniAPI.postAndGetJSON(endpoint, payload)
18
- : zeniAPI.putAndGetJSON(endpoint, payload);
19
- return request$.pipe(mergeMap((response) => {
20
- if (isSuccessResponse(response) && response.data != null) {
21
- return of(updateAutoSweepSettingsFetchStatus({ fetchState: 'Completed' }));
22
- }
23
- return of(updateAutoSweepSettingsFetchStatus({
24
- fetchState: 'Error',
25
- error: response?.status,
26
- }));
27
- }), catchError((error) => of(updateAutoSweepSettingsFetchStatus({
28
- fetchState: 'Error',
29
- error: createZeniAPIStatus('Unexpected Error', 'Save auto-sweep settings REST API call errored out: ' +
30
- (error?.message ?? String(error))),
31
- }))));
32
- }));
@@ -1,54 +0,0 @@
1
- import { toAmount } from '../../../../commonStateTypes/amount';
2
- import { date as zeniDate } from '../../../../zeniDayJS';
3
- // ---------------------------------------------------------------------------
4
- // Converters
5
- // ---------------------------------------------------------------------------
6
- // The cash agent payload reports `currency_code` only; the v1 surface is
7
- // USD-only, so we pair it with the canonical `$` symbol here. If the agent
8
- // grows multi-currency support, this is the single place to widen.
9
- const CASH_AGENT_CURRENCY_SYMBOL = '$';
10
- export const toUpcomingPaymentEvent = (event) => ({
11
- accountId: event.account_id,
12
- accountType: event.account_type,
13
- amount: toAmount(event.amount_usd, event.currency_code, CASH_AGENT_CURRENCY_SYMBOL),
14
- label: event.label,
15
- paymentDate: zeniDate(event.payment_date),
16
- });
17
- /**
18
- * The agent reports a `null` account id whenever the "account" in question is
19
- * a singleton inferred from the account type (today: the treasury account —
20
- * there's only one per company, so the type alone identifies it). Callers
21
- * already branch on `*BankAccountType`, so collapsing the id to `""` keeps the
22
- * state type a plain `ID` (string) without losing information.
23
- */
24
- const toCashManagementMovement = (payload) => ({
25
- amount: toAmount(payload.amount, payload.currency_code, CASH_AGENT_CURRENCY_SYMBOL),
26
- destinationBankAccountId: payload.destination_bank_account_id ?? '',
27
- destinationBankAccountType: payload.destination_bank_account_type,
28
- reasoning: payload.reasoning,
29
- sourceBankAccountId: payload.source_bank_account_id ?? '',
30
- sourceBankAccountType: payload.source_bank_account_type,
31
- subMovementType: payload.sub_movement_type,
32
- });
33
- const toCashManagementMoneyMovementGroup = (payload) => ({
34
- movements: payload.movements.map(toCashManagementMovement),
35
- movementType: payload.movement_type,
36
- });
37
- export const toCashManagementBannerData = (payload) => ({
38
- inflows: payload.inflows.map(toUpcomingPaymentEvent),
39
- moneyMovements: payload.money_movements.map(toCashManagementMoneyMovementGroup),
40
- outflows: payload.outflows.map(toUpcomingPaymentEvent),
41
- });
42
- export const toCashManagementTransfer = (payload) => ({
43
- amount: toAmount(payload.amount, payload.currency_code, CASH_AGENT_CURRENCY_SYMBOL),
44
- atomicTransactionId: payload.atomic_transaction_id,
45
- cashManagementTransferId: payload.cash_management_transfer_id,
46
- createTime: zeniDate(payload.create_time),
47
- date: zeniDate(payload.date),
48
- depositAccountId: payload.deposit_account_id,
49
- reasoning: payload.reasoning,
50
- scenario: payload.scenario,
51
- status: payload.status,
52
- transactionType: payload.transaction_type,
53
- updateTime: zeniDate(payload.update_time),
54
- });
@@ -1,92 +0,0 @@
1
- import { createSlice } from '@reduxjs/toolkit';
2
- import { toCashManagementBannerData, toCashManagementTransfer, } from './cashManagementOverviewPayload';
3
- import { initialCashManagementBannerState, initialCashManagementRecentTransferState, } from './cashManagementOverviewState';
4
- export const initialState = {
5
- banner: initialCashManagementBannerState,
6
- recentTransfer: initialCashManagementRecentTransferState,
7
- };
8
- const cashManagementOverview = createSlice({
9
- name: 'cashManagementOverview',
10
- initialState,
11
- reducers: {
12
- fetchCashManagementOverviewPage: {
13
- reducer() { },
14
- prepare(cacheOverride) {
15
- return { payload: { cacheOverride } };
16
- },
17
- },
18
- /**
19
- * Public banner-fetch entry point. Triggers an orchestrator epic that
20
- * fans out to the recommend, settings, and recent-transfer API calls
21
- * in parallel. No reducer-side state change — each inner action drives
22
- * its own sub-state.
23
- *
24
- * `cacheOverride === true` forces all three inner fetches regardless
25
- * of current slice state; `false` keeps the per-slice dedup so repeat
26
- * dispatches are no-ops once a slice is loaded or in-flight.
27
- */
28
- fetchCashManagementBanner: {
29
- reducer() { },
30
- prepare(cacheOverride) {
31
- return { payload: { cacheOverride } };
32
- },
33
- },
34
- /**
35
- * Internal trigger for the recommend API (`/cash-agent/recommend`).
36
- * Dispatched by the orchestrator; not exported.
37
- */
38
- fetchCashManagementRecommendation(draft) {
39
- // Keep `draft.banner.data` so the projection chart renders the last
40
- // good payload while the refetch is in flight, instead of flickering
41
- // to the empty/skeleton state on every page revisit.
42
- draft.banner.fetchState = 'In-Progress';
43
- draft.banner.error = undefined;
44
- },
45
- updateCashManagementRecommendation(draft, action) {
46
- draft.banner = {
47
- fetchState: 'Completed',
48
- error: undefined,
49
- data: toCashManagementBannerData(action.payload.data),
50
- };
51
- },
52
- updateCashManagementRecommendationFetchStatus(draft, action) {
53
- draft.banner = {
54
- ...draft.banner,
55
- fetchState: action.payload.fetchState,
56
- error: action.payload.error,
57
- };
58
- },
59
- /**
60
- * Internal trigger for the recent-transfer API
61
- * (`/cash-management/transfers`). Dispatched by the orchestrator; not
62
- * exported.
63
- */
64
- fetchRecentTransfer(draft) {
65
- // Same anti-flicker pattern as the recommend fetch: keep prior data
66
- // while the refetch is in flight.
67
- draft.recentTransfer.fetchState = 'In-Progress';
68
- draft.recentTransfer.error = undefined;
69
- },
70
- updateRecentTransfer(draft, action) {
71
- draft.recentTransfer = {
72
- fetchState: 'Completed',
73
- error: undefined,
74
- data: action.payload.data != null
75
- ? toCashManagementTransfer(action.payload.data)
76
- : undefined,
77
- };
78
- },
79
- updateRecentTransferFetchStatus(draft, action) {
80
- draft.recentTransfer = {
81
- ...draft.recentTransfer,
82
- fetchState: action.payload.fetchState,
83
- error: action.payload.error,
84
- };
85
- },
86
- clearCashManagementOverview(draft) {
87
- Object.assign(draft, initialState);
88
- },
89
- },
90
- });
91
- export const { fetchCashManagementOverviewPage, fetchCashManagementBanner, fetchCashManagementRecommendation, updateCashManagementRecommendation, updateCashManagementRecommendationFetchStatus, fetchRecentTransfer, updateRecentTransfer, updateRecentTransferFetchStatus, clearCashManagementOverview, } = cashManagementOverview.actions;
92
- export default cashManagementOverview.reducer;