@zeniai/client-epic-state 5.2.93 → 5.2.94-beta0MM

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 (86) hide show
  1. package/lib/commonStateTypes/timeframeTick.d.ts +1 -0
  2. package/lib/commonStateTypes/timeframeTick.js +1 -0
  3. package/lib/commonStateTypes/viewAndReport/reportUIState.d.ts +2 -0
  4. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -0
  5. package/lib/esm/commonStateTypes/timeframeTick.js +1 -0
  6. package/lib/esm/view/balanceSheet/balanceSheetForTimeframeEpic.js +4 -0
  7. package/lib/esm/view/balanceSheet/balanceSheetReducer.js +8 -2
  8. package/lib/esm/view/cashFlow/cashFlowForTimeframeEpic.js +4 -0
  9. package/lib/esm/view/cashFlow/cashFlowReducer.js +2 -2
  10. package/lib/esm/view/cashInCashOut/cashInCashOutEpic.js +22 -14
  11. package/lib/esm/view/cashInCashOut/cashInCashOutReducer.js +161 -41
  12. package/lib/esm/view/cashInCashOut/cashInCashOutSelector.js +42 -15
  13. package/lib/esm/view/cashPosition/cashPositionEpic.js +21 -13
  14. package/lib/esm/view/cashPosition/cashPositionReducer.js +155 -44
  15. package/lib/esm/view/cashPosition/cashPositionSelector.js +28 -9
  16. package/lib/esm/view/expenseAutomationView/payload/actualMatchingPayload.js +5 -0
  17. package/lib/esm/view/netBurnOrIncome/netBurnOrIncomeEpic.js +7 -7
  18. package/lib/esm/view/netBurnOrIncome/netBurnOrIncomeForTimeframeEpic.js +25 -10
  19. package/lib/esm/view/netBurnOrIncome/netBurnOrIncomeReducer.js +184 -40
  20. package/lib/esm/view/netBurnOrIncome/netBurnOrIncomeSelector.js +26 -8
  21. package/lib/esm/view/opEx/opExEpic.js +7 -7
  22. package/lib/esm/view/opEx/opExForTimeFrameEpic.js +21 -6
  23. package/lib/esm/view/opEx/opExReducer.js +169 -32
  24. package/lib/esm/view/opEx/opExSelector.js +28 -10
  25. package/lib/esm/view/profitAndLoss/profitAndLossForTimeframeEpic.js +4 -0
  26. package/lib/esm/view/profitAndLoss/profitAndLossReducer.js +9 -2
  27. package/lib/esm/view/revenue/revenueEpic.js +7 -7
  28. package/lib/esm/view/revenue/revenueForTimeframeEpic.js +23 -8
  29. package/lib/esm/view/revenue/revenueReducer.js +183 -40
  30. package/lib/esm/view/revenue/revenueSelector.js +30 -10
  31. package/lib/view/balanceSheet/balanceSheetForTimeframeEpic.js +4 -0
  32. package/lib/view/balanceSheet/balanceSheetReducer.d.ts +3 -1
  33. package/lib/view/balanceSheet/balanceSheetReducer.js +8 -2
  34. package/lib/view/cashFlow/cashFlowForTimeframeEpic.js +4 -0
  35. package/lib/view/cashFlow/cashFlowReducer.d.ts +3 -1
  36. package/lib/view/cashFlow/cashFlowReducer.js +2 -2
  37. package/lib/view/cashInCashOut/cashInCashOutEpic.d.ts +8 -2
  38. package/lib/view/cashInCashOut/cashInCashOutEpic.js +22 -14
  39. package/lib/view/cashInCashOut/cashInCashOutReducer.d.ts +13 -1
  40. package/lib/view/cashInCashOut/cashInCashOutReducer.js +161 -41
  41. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +2 -1
  42. package/lib/view/cashInCashOut/cashInCashOutSelector.js +42 -15
  43. package/lib/view/cashInCashOut/cashInCashOutState.d.ts +5 -1
  44. package/lib/view/cashPosition/cashPositionEpic.d.ts +8 -2
  45. package/lib/view/cashPosition/cashPositionEpic.js +21 -13
  46. package/lib/view/cashPosition/cashPositionReducer.d.ts +13 -2
  47. package/lib/view/cashPosition/cashPositionReducer.js +155 -44
  48. package/lib/view/cashPosition/cashPositionSelector.d.ts +2 -1
  49. package/lib/view/cashPosition/cashPositionSelector.js +28 -9
  50. package/lib/view/cashPosition/cashPositionState.d.ts +5 -1
  51. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +2 -0
  52. package/lib/view/expenseAutomationView/payload/actualMatchingPayload.js +5 -0
  53. package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +3 -0
  54. package/lib/view/financeStatement/financeStatementEpic.d.ts +6 -0
  55. package/lib/view/netBurnOrIncome/fetchNetBurnOrIncomeWithForecastEpic.d.ts +1 -0
  56. package/lib/view/netBurnOrIncome/netBurnOrIncomeEpic.js +7 -7
  57. package/lib/view/netBurnOrIncome/netBurnOrIncomeForTimeframeEpic.d.ts +2 -1
  58. package/lib/view/netBurnOrIncome/netBurnOrIncomeForTimeframeEpic.js +26 -11
  59. package/lib/view/netBurnOrIncome/netBurnOrIncomeReducer.d.ts +12 -3
  60. package/lib/view/netBurnOrIncome/netBurnOrIncomeReducer.js +184 -40
  61. package/lib/view/netBurnOrIncome/netBurnOrIncomeSelector.d.ts +1 -1
  62. package/lib/view/netBurnOrIncome/netBurnOrIncomeSelector.js +26 -8
  63. package/lib/view/netBurnOrIncome/netBurnOrIncomeState.d.ts +8 -0
  64. package/lib/view/opEx/fetchOpExWithForecastEpic.d.ts +1 -0
  65. package/lib/view/opEx/opExEpic.js +7 -7
  66. package/lib/view/opEx/opExForTimeFrameEpic.d.ts +2 -1
  67. package/lib/view/opEx/opExForTimeFrameEpic.js +22 -7
  68. package/lib/view/opEx/opExReducer.d.ts +12 -3
  69. package/lib/view/opEx/opExReducer.js +168 -31
  70. package/lib/view/opEx/opExSelector.d.ts +1 -1
  71. package/lib/view/opEx/opExSelector.js +28 -10
  72. package/lib/view/opEx/opExState.d.ts +6 -0
  73. package/lib/view/profitAndLoss/profitAndLossForTimeframeEpic.js +4 -0
  74. package/lib/view/profitAndLoss/profitAndLossReducer.d.ts +3 -1
  75. package/lib/view/profitAndLoss/profitAndLossReducer.js +9 -2
  76. package/lib/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.d.ts +15 -0
  77. package/lib/view/revenue/fetchRevenueWithForecastEpic.d.ts +1 -0
  78. package/lib/view/revenue/revenueEpic.js +7 -7
  79. package/lib/view/revenue/revenueForTimeframeEpic.d.ts +2 -1
  80. package/lib/view/revenue/revenueForTimeframeEpic.js +24 -9
  81. package/lib/view/revenue/revenueReducer.d.ts +12 -3
  82. package/lib/view/revenue/revenueReducer.js +182 -39
  83. package/lib/view/revenue/revenueSelector.d.ts +1 -1
  84. package/lib/view/revenue/revenueSelector.js +30 -10
  85. package/lib/view/revenue/revenueState.d.ts +8 -0
  86. package/package.json +1 -1
@@ -96,8 +96,16 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
96
96
  },
97
97
  },
98
98
  fetchNetBurnOrIncome: {
99
- prepare(fetchFullReport = false, forecastId, cacheOverride = false) {
100
- return { payload: { fetchFullReport, forecastId, cacheOverride } };
99
+ prepare(fetchFullReport = false, forecastId, cacheOverride = false, startDate, endDate) {
100
+ return {
101
+ payload: {
102
+ fetchFullReport,
103
+ forecastId,
104
+ cacheOverride,
105
+ startDate,
106
+ endDate,
107
+ },
108
+ };
101
109
  },
102
110
  reducer(
103
111
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -108,50 +116,138 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
108
116
  },
109
117
  },
110
118
  fetchNetBurnOrIncomeForTimeframe: {
111
- prepare(timeframe, forecastId, fetchFullReport = true, cacheOverride = false) {
119
+ prepare(timeframe, forecastId, fetchFullReport = true, cacheOverride = false, startDate, endDate) {
112
120
  return {
113
- payload: { forecastId, timeframe, fetchFullReport, cacheOverride },
121
+ payload: {
122
+ forecastId,
123
+ timeframe,
124
+ fetchFullReport,
125
+ cacheOverride,
126
+ startDate,
127
+ endDate,
128
+ },
114
129
  };
115
130
  },
116
131
  reducer(draft, action) {
117
132
  const timeframe = action.payload.timeframe;
118
133
  const netBurnOrIncomeState = getState(draft, draft.uiState.isForecastModeOn, action.payload.forecastId);
119
- const fetchState = {
120
- ...netBurnOrIncomeState.fetchState,
121
- };
122
- fetchState[timeframe] = {
123
- fetchState: 'In-Progress',
124
- error: undefined,
125
- };
126
- updateState(draft, action.payload.forecastId, { fetchState });
134
+ // Route by the fetch's own dates, not the global flag: a custom fetch
135
+ // (carries start/end) marks customFetchState so the shared fetchState the
136
+ // dashboard reads is never left In-Progress by a detail-screen fetch.
137
+ const isCustomDateRange = action.payload.startDate != null && action.payload.endDate != null;
138
+ if (isCustomDateRange) {
139
+ const customFetchState = {
140
+ ...(netBurnOrIncomeState.customFetchState ?? {
141
+ month: { fetchState: 'Not-Started', error: undefined },
142
+ quarter: { fetchState: 'Not-Started', error: undefined },
143
+ year: { fetchState: 'Not-Started', error: undefined },
144
+ }),
145
+ };
146
+ customFetchState[timeframe] = {
147
+ fetchState: 'In-Progress',
148
+ error: undefined,
149
+ };
150
+ updateState(draft, action.payload.forecastId, { customFetchState });
151
+ }
152
+ else {
153
+ const fetchState = {
154
+ ...netBurnOrIncomeState.fetchState,
155
+ };
156
+ fetchState[timeframe] = {
157
+ fetchState: 'In-Progress',
158
+ error: undefined,
159
+ };
160
+ updateState(draft, action.payload.forecastId, { fetchState });
161
+ }
127
162
  },
128
163
  },
129
164
  updateNetBurnOrIncomeForTimeframe(draft, action) {
130
- doUpdateNetBurnOrIncome(draft, action.payload.forecastId, action.payload.timeframe, action.payload.report);
165
+ doUpdateNetBurnOrIncome(draft, action.payload.forecastId, action.payload.timeframe, action.payload.report, action.payload.isCustomDateRange === true);
131
166
  },
132
167
  updateNetBurnOrIncomeForTimeframeFailure: {
133
- prepare(error, forecastId, timeframe) {
168
+ prepare(error, forecastId, timeframe, isCustomDateRange = false) {
134
169
  return {
135
170
  payload: {
136
171
  error,
137
172
  forecastId,
138
173
  timeframe,
174
+ isCustomDateRange,
139
175
  },
140
176
  };
141
177
  },
142
178
  reducer(draft, action) {
143
179
  const netBurnOrIncome = getState(draft, draft.uiState.isForecastModeOn, action.payload.forecastId);
144
- const fetchState = {
145
- ...netBurnOrIncome.fetchState,
146
- };
147
- fetchState[action.payload.timeframe] = {
148
- fetchState: 'Error',
149
- error: action.payload.error,
150
- };
151
- updateState(draft, action.payload.forecastId, { fetchState });
180
+ // Route the error like the request/success: a custom (dated) fetch's
181
+ // failure lands in customFetchState so the shared default the dashboard
182
+ // reads isn't marked Error, and the detail's customFetchState isn't left
183
+ // stuck In-Progress.
184
+ if (action.payload.isCustomDateRange === true) {
185
+ const customFetchState = netBurnOrIncome.customFetchState ?? {
186
+ month: { fetchState: 'Not-Started', error: undefined },
187
+ quarter: { fetchState: 'Not-Started', error: undefined },
188
+ year: { fetchState: 'Not-Started', error: undefined },
189
+ };
190
+ customFetchState[action.payload.timeframe] = {
191
+ fetchState: 'Error',
192
+ error: action.payload.error,
193
+ };
194
+ updateState(draft, action.payload.forecastId, { customFetchState });
195
+ }
196
+ else {
197
+ const fetchState = {
198
+ ...netBurnOrIncome.fetchState,
199
+ };
200
+ fetchState[action.payload.timeframe] = {
201
+ fetchState: 'Error',
202
+ error: action.payload.error,
203
+ };
204
+ updateState(draft, action.payload.forecastId, { fetchState });
205
+ }
152
206
  },
153
207
  },
154
208
  updateNetBurnOrIncomeCOABalancesRange(draft, action) {
209
+ if (action.payload.isCustomDateRange != null) {
210
+ if (action.payload.isCustomDateRange === true) {
211
+ // Convert the string dates the action carries to ZeniDate values and
212
+ // store as a single customTimeframe. Presence signals custom-mode active.
213
+ draft.uiState.customTimeframe =
214
+ action.payload.customStartDate != null &&
215
+ action.payload.customEndDate != null
216
+ ? {
217
+ startDate: (0, zeniDayJS_1.date)(action.payload.customStartDate),
218
+ endDate: (0, zeniDayJS_1.date)(action.payload.customEndDate),
219
+ }
220
+ : undefined;
221
+ // Invalidate the shared default-window fetchState so dashboardEpic
222
+ // refetches the default data on the next dashboard visit — the custom
223
+ // fetch writes into the shared section store, and this lets the card
224
+ // self-heal without a reload. The detail screen reads customFetchState.
225
+ draft.netBurnOrIncome.fetchState = {
226
+ month: { fetchState: 'Not-Started', error: undefined },
227
+ quarter: { fetchState: 'Not-Started', error: undefined },
228
+ year: { fetchState: 'Not-Started', error: undefined },
229
+ };
230
+ }
231
+ else {
232
+ draft.uiState.customTimeframe = undefined;
233
+ }
234
+ }
235
+ // A custom date range drives the visible window directly: honor the exact
236
+ // numberOfPeriods + thisPeriod from the payload instead of re-deriving
237
+ // (which clamps the range to the available/non-zero periods).
238
+ if (draft.uiState.customTimeframe != null) {
239
+ draft.uiState.selectedCOABalancesRange =
240
+ action.payload.selectedCOABalancesRange;
241
+ if (action.payload.highlightedCOABalancesRange != null) {
242
+ // Clamp the highlight to the same cap the non-custom path enforces so
243
+ // a wide custom range doesn't highlight all N periods at once.
244
+ draft.uiState.highlightedCOABalancesRange = {
245
+ ...action.payload.highlightedCOABalancesRange,
246
+ numberOfPeriods: Math.min(action.payload.highlightedCOABalancesRange.numberOfPeriods, draft.uiState.maxNumOfPeriodsToHighlight),
247
+ };
248
+ }
249
+ return;
250
+ }
155
251
  // When thisPeriod changes the selected and highlighted balances ranges should be calculated based on full report period.
156
252
  const netBurnOrIncomeReport = getState(draft, undefined, undefined);
157
253
  const { income, cogs, expenses, dataAvailable } = netBurnOrIncomeReport;
@@ -195,6 +291,13 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
195
291
  }
196
292
  },
197
293
  updateNetBurnOrIncomeThisPeriod(draft, action) {
294
+ // In custom-date mode the picker drives the window; skip re-deriving the
295
+ // selected/highlighted ranges from the default dataAvailable (the epic
296
+ // re-dispatches the default thisPeriod on every month response, which
297
+ // would otherwise clamp the custom window back to the default).
298
+ if (draft.uiState.customTimeframe != null) {
299
+ return;
300
+ }
198
301
  // When thisPeriod changes the selected and highlighted balances ranges should be calculated based on full report period.
199
302
  const netBurnOrIncomeReport = getState(draft, undefined, undefined);
200
303
  const { income, cogs, expenses, dataAvailable } = netBurnOrIncomeReport;
@@ -246,7 +349,9 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
246
349
  ? true
247
350
  : false;
248
351
  // Note: We don't want to update selected & highlighted ranges in Ui State when forecast is ON
249
- if (dataAvailable != null && draft.uiState.isForecastModeOn === false) {
352
+ if (dataAvailable != null &&
353
+ draft.uiState.isForecastModeOn === false &&
354
+ draft.uiState.customTimeframe == null) {
250
355
  const coaBalances = (0, getSelectedAndHighlightedRanges_1.getAvailableCOABalancesWithMostRecentNonZeroBalance)(netBurnOrIncomeReport.firstMonthOfFY, timeframe, [expenses, income, cogs], dataAvailable);
251
356
  const thisPeriod = (0, thisPeriodHelpers_1.extractThisPeriod)(netBurnOrIncomeReport.firstMonthOfFY, timeframe, selectedCOABalancesRange, coaBalances);
252
357
  if (thisPeriod != null &&
@@ -289,7 +394,7 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
289
394
  draft.uiState.maxNumOfPeriodsToHighlight =
290
395
  exports.initialState.uiState.maxNumOfPeriodsToHighlight;
291
396
  }
292
- if (dataAvailable != null) {
397
+ if (dataAvailable != null && draft.uiState.customTimeframe == null) {
293
398
  const timeframe = draft.uiState.timeframe;
294
399
  const coaBalances = (0, getSelectedAndHighlightedRanges_1.getAvailableCOABalancesWithMostRecentNonZeroBalance)(netBurnOrIncomeReport.firstMonthOfFY, timeframe, [expenses, income, cogs], dataAvailable);
295
400
  const selectionRanges = (0, getSelectedAndHighlightedRanges_1.getInitialSelectedAndHighlightedRanges)({
@@ -344,34 +449,73 @@ const netBurnOrIncome = (0, toolkit_1.createSlice)({
344
449
  });
345
450
  _a = netBurnOrIncome.actions, exports.fetchNetBurnOrIncome = _a.fetchNetBurnOrIncome, exports.fetchNetBurnOrIncomeForTimeframe = _a.fetchNetBurnOrIncomeForTimeframe, exports.updateNetBurnOrIncomeForTimeframe = _a.updateNetBurnOrIncomeForTimeframe, exports.updateNetBurnOrIncomeForTimeframeFailure = _a.updateNetBurnOrIncomeForTimeframeFailure, exports.updateNetBurnOrIncomeThisPeriod = _a.updateNetBurnOrIncomeThisPeriod, exports.updateNetBurnOrIncomeUIState = _a.updateNetBurnOrIncomeUIState, exports.updateNetBurnOrIncomeAdditionalBalancesSelection = _a.updateNetBurnOrIncomeAdditionalBalancesSelection, exports.updateNetBurnOrIncomeCOABalancesRange = _a.updateNetBurnOrIncomeCOABalancesRange, exports.netBurnOrIncomeToggleForecastMode = _a.netBurnOrIncomeToggleForecastMode, exports.updateNetBurnOrIncomeTimeFrame = _a.updateNetBurnOrIncomeTimeFrame, exports.updateNetBurnOrIncomeDownloadState = _a.updateNetBurnOrIncomeDownloadState, exports.fetchNetBurnOrIncomeWithForecast = _a.fetchNetBurnOrIncomeWithForecast, exports.waitForForecastListThenFetchNetBurnOrIncomeWithForecast = _a.waitForForecastListThenFetchNetBurnOrIncomeWithForecast;
346
451
  exports.default = netBurnOrIncome.reducer;
347
- const doUpdateNetBurnOrIncome = (draft, forecastId, timeframe, data) => {
452
+ const doUpdateNetBurnOrIncome = (draft, forecastId, timeframe, data, isCustomDateRange) => {
348
453
  const netBurnOrIncome = getState(draft, draft.uiState.isForecastModeOn, forecastId);
349
454
  const report = (0, viewAndReportPayloadv2_1.mapReportPayloadV2ToReportV2)(data.report);
350
455
  const { expenses, income, cogs, net_burn_or_income, insights, currency, runway, } = data.report;
351
456
  const expensesCOABalance = (0, coaBalancePayload_1.mapCOABalanceGroupedByPeriodPayloadV2ToCOABalanceGroupedByPeriod)(expenses, currency, timeframe);
352
457
  const incomeCOABalance = (0, coaBalancePayload_1.mapCOABalanceGroupedByPeriodPayloadV2ToCOABalanceGroupedByPeriod)(income, currency, timeframe);
353
458
  const cogsCOABalance = (0, coaBalancePayload_1.mapCOABalanceGroupedByPeriodPayloadV2ToCOABalanceGroupedByPeriod)(cogs, currency, timeframe);
354
- netBurnOrIncome.expenses = Object.assign({}, netBurnOrIncome.expenses, expensesCOABalance);
355
- netBurnOrIncome.income = Object.assign({}, netBurnOrIncome.income, incomeCOABalance);
356
- netBurnOrIncome.cogs = Object.assign({}, netBurnOrIncome.cogs, cogsCOABalance);
357
- if (timeframe === 'month' && insights != null) {
459
+ // Route custom-date results (identified by the fetch's own dates, not the
460
+ // global flag) to the separate slots so the dashboard card (which reads
461
+ // income/cogs/expenses) keeps the default window.
462
+ if (isCustomDateRange) {
463
+ netBurnOrIncome.customExpenses = Object.assign({}, netBurnOrIncome.customExpenses, expensesCOABalance);
464
+ netBurnOrIncome.customIncome = Object.assign({}, netBurnOrIncome.customIncome, incomeCOABalance);
465
+ netBurnOrIncome.customCogs = Object.assign({}, netBurnOrIncome.customCogs, cogsCOABalance);
466
+ }
467
+ else {
468
+ netBurnOrIncome.expenses = Object.assign({}, netBurnOrIncome.expenses, expensesCOABalance);
469
+ netBurnOrIncome.income = Object.assign({}, netBurnOrIncome.income, incomeCOABalance);
470
+ netBurnOrIncome.cogs = Object.assign({}, netBurnOrIncome.cogs, cogsCOABalance);
471
+ }
472
+ // Insights and runway/averages are shared (read by the dashboard card); a
473
+ // custom-date slice must not overwrite them with its partial window.
474
+ if (timeframe === 'month' && insights != null && !isCustomDateRange) {
358
475
  // we will get insights only in the month timeframe api
359
476
  netBurnOrIncome.insights = (0, insightSummaryPayload_1.mapInsightsPayloadtoInsightsState)(insights);
360
477
  }
361
- netBurnOrIncome.runwayAndAverages = mapRunwayPayloadtoRunwayState(runway, net_burn_or_income.averages?.months, data.report.currency);
362
- const expensesOrIncome = netBurnOrIncome.expenses != null
363
- ? netBurnOrIncome.expenses
364
- : netBurnOrIncome.income;
365
- netBurnOrIncome.dataAvailable = report.dataAvailable
366
- ? report.dataAvailable
367
- : (0, dataAvailable_1.getDataAvailableDateRange)(expensesOrIncome);
478
+ if (!isCustomDateRange) {
479
+ netBurnOrIncome.runwayAndAverages = mapRunwayPayloadtoRunwayState(runway, net_burn_or_income.averages?.months, data.report.currency);
480
+ }
481
+ // Derive dataAvailable from the slot this fetch actually populated.
482
+ const expensesOrIncome = isCustomDateRange
483
+ ? netBurnOrIncome.customExpenses != null
484
+ ? netBurnOrIncome.customExpenses
485
+ : netBurnOrIncome.customIncome
486
+ : netBurnOrIncome.expenses != null
487
+ ? netBurnOrIncome.expenses
488
+ : netBurnOrIncome.income;
489
+ // Don't let a custom slice shrink the shared dataAvailable the dashboard uses
490
+ // for its period count; a default fetch always updates it, a custom one only
491
+ // populates it on first load (when nothing has set it yet).
492
+ if (!isCustomDateRange || netBurnOrIncome.dataAvailable == null) {
493
+ netBurnOrIncome.dataAvailable = report.dataAvailable
494
+ ? report.dataAvailable
495
+ : (0, dataAvailable_1.getDataAvailableDateRange)(expensesOrIncome ?? {});
496
+ }
368
497
  netBurnOrIncome.firstMonthOfFY = report.firstMonthOfFY;
369
498
  netBurnOrIncome.bookCloseDate = report.bookCloseDate;
370
- netBurnOrIncome.fetchState[timeframe].fetchState = 'Completed';
371
- netBurnOrIncome.fetchState[timeframe].error = undefined;
499
+ // Mark the matching fetchState Completed. A custom fetch uses customFetchState so
500
+ // dashboardEpic's Completed check on the default fetchState is untouched.
501
+ if (isCustomDateRange) {
502
+ const customFetchState = netBurnOrIncome.customFetchState ?? {
503
+ month: { fetchState: 'Not-Started', error: undefined },
504
+ quarter: { fetchState: 'Not-Started', error: undefined },
505
+ year: { fetchState: 'Not-Started', error: undefined },
506
+ };
507
+ customFetchState[timeframe] = { fetchState: 'Completed', error: undefined };
508
+ netBurnOrIncome.customFetchState = customFetchState;
509
+ }
510
+ else {
511
+ netBurnOrIncome.fetchState[timeframe].fetchState = 'Completed';
512
+ netBurnOrIncome.fetchState[timeframe].error = undefined;
513
+ }
372
514
  if (netBurnOrIncome.dataAvailable != null &&
373
- forecastId == null // Note: We don't want to update selected & highlighted ranges in Ui State when forecast is ON
374
- ) {
515
+ forecastId == null && // Note: We don't want to update selected & highlighted ranges in Ui State when forecast is ON
516
+ // A custom date range drives the window; don't reset it to the default on
517
+ // every report receipt (this is what clamped wide ranges back to 8).
518
+ draft.uiState.customTimeframe == null) {
375
519
  const timeframe = draft.uiState.timeframe;
376
520
  const coaBalances = (0, getSelectedAndHighlightedRanges_1.getAvailableCOABalancesWithMostRecentNonZeroBalance)(netBurnOrIncome.firstMonthOfFY, timeframe, [netBurnOrIncome.expenses, netBurnOrIncome.income, netBurnOrIncome.cogs], netBurnOrIncome.dataAvailable);
377
521
  const selectionRanges = (0, getSelectedAndHighlightedRanges_1.getInitialSelectedAndHighlightedRanges)({
@@ -9,7 +9,7 @@ import { ForecastListState } from '../forecastList/forecastListState';
9
9
  import { NetBurnOrIncomeReport, NetBurnOrIncomeUIStateSelectorView } from './netBurnOrIncomeSelectorTypes';
10
10
  import { NetBurnOrIncomeWithForecastState } from './netBurnOrIncomeState';
11
11
  export declare const getNetBurnOrIncomeUIState: (state: RootState) => NetBurnOrIncomeUIStateSelectorView;
12
- export declare const getNetBurnOrIncomeReport: (accountState: AccountState, accountGroupState: AccountGroupState, sectionsState: SectionAccountsViewState, netBurnOrIncomeState: NetBurnOrIncomeWithForecastState, forecastState: ForecastState, forecastListState: ForecastListState, filter: COABalancesFilter, forecastId?: ID) => NetBurnOrIncomeReport;
12
+ export declare const getNetBurnOrIncomeReport: (accountState: AccountState, accountGroupState: AccountGroupState, sectionsState: SectionAccountsViewState, netBurnOrIncomeState: NetBurnOrIncomeWithForecastState, forecastState: ForecastState, forecastListState: ForecastListState, filter: COABalancesFilter, forecastId?: ID, readCustomRangeSlot?: boolean) => NetBurnOrIncomeReport;
13
13
  export declare const getNetBurnOrIncomeForSelectedRange: (state: RootState) => NetBurnOrIncomeReport;
14
14
  export declare const getNetBurnOrIncomeForHighlightedRange: (state: RootState) => NetBurnOrIncomeReport;
15
15
  export declare const getNetBurnOrIncomeReportFetchState: (forecastId: ID | undefined, netBurnOrIncomeState: NetBurnOrIncomeWithForecastState) => FetchStateAndError;
@@ -63,18 +63,28 @@ exports.getNetBurnOrIncomeUIState = (0, toolkit_1.createSelector)((state) => sta
63
63
  scrollPosition,
64
64
  };
65
65
  });
66
- const getNetBurnOrIncomeReport = (accountState, accountGroupState, sectionsState, netBurnOrIncomeState, forecastState, forecastListState, filter, forecastId) => {
66
+ const getNetBurnOrIncomeReport = (accountState, accountGroupState, sectionsState, netBurnOrIncomeState, forecastState, forecastListState, filter, forecastId, readCustomRangeSlot) => {
67
67
  const netBurnOrIncome = (0, netBurnOrIncomeReducer_1.getState)(netBurnOrIncomeState, netBurnOrIncomeState.uiState.isForecastModeOn, forecastId);
68
+ // Custom detail reads the isolated custom section-accounts slot; dashboard
69
+ // (no flag) reads the default slot, so a default fetch can't clobber it.
70
+ const useCustomRange = readCustomRangeSlot === true &&
71
+ netBurnOrIncomeState.uiState.customTimeframe != null;
72
+ // The detail screen opts into customFetchState so its Completed check fires
73
+ // off the custom fetch; the dashboard (no flag) reads the shared fetchState,
74
+ // which custom-mode activation reset to Not-Started so dashboardEpic refetches.
75
+ const activeFetchState = useCustomRange && netBurnOrIncome.customFetchState != null
76
+ ? netBurnOrIncome.customFetchState
77
+ : netBurnOrIncome.fetchState;
68
78
  const fetchState = (0, reduceFetchState_1.reduceAnyFetchState)([
69
- netBurnOrIncome.fetchState.month,
70
- netBurnOrIncome.fetchState.quarter,
71
- netBurnOrIncome.fetchState.year,
79
+ activeFetchState.month,
80
+ activeFetchState.quarter,
81
+ activeFetchState.year,
72
82
  ]);
73
83
  let allTimeframeTicks = [];
74
84
  const dataAvailable = netBurnOrIncomeState.netBurnOrIncome.dataAvailable;
75
85
  if (dataAvailable != null) {
76
86
  const noFilter = (0, coaBalancesFilter_1.newBalancesFilterForDateRange)(netBurnOrIncomeState.netBurnOrIncome.firstMonthOfFY, netBurnOrIncomeState.uiState.timeframe, dataAvailable, 'ascending_date', []);
77
- const reportId = (0, netBurnOrIncomeForTimeframeEpic_1.reportIdUniqueKey)();
87
+ const reportId = (0, netBurnOrIncomeForTimeframeEpic_1.reportIdUniqueKey)(undefined, useCustomRange);
78
88
  const incomeBalance = (0, sectionAccountsViewSelector_1.getSectionBalances)(sectionsState, {
79
89
  reportId,
80
90
  sectionId: 'income',
@@ -91,7 +101,7 @@ const getNetBurnOrIncomeReport = (accountState, accountGroupState, sectionsState
91
101
  : (0, getCOABalancesSlice_1.getCOABalances)(incomeBalance, noFilter);
92
102
  allTimeframeTicks = incomeOrExpensesBalances.balances.map((balance) => (0, timeframeTick_1.toTimeframeTick)(balance));
93
103
  }
94
- const reportId = (0, netBurnOrIncomeForTimeframeEpic_1.reportIdUniqueKey)(forecastId);
104
+ const reportId = (0, netBurnOrIncomeForTimeframeEpic_1.reportIdUniqueKey)(forecastId, useCustomRange);
95
105
  const sections = {};
96
106
  const calculatedSections = {};
97
107
  if (fetchState.fetchState === 'Completed') {
@@ -138,6 +148,8 @@ const getNetBurnOrIncomeReport = (accountState, accountGroupState, sectionsState
138
148
  allTimeframeTicks,
139
149
  forecastList,
140
150
  runwayAndAverages: netBurnOrIncome.runwayAndAverages,
151
+ // Surface the saved custom timeframe so the detail picker can restore them.
152
+ customTimeframe: netBurnOrIncomeState.uiState.customTimeframe,
141
153
  };
142
154
  };
143
155
  exports.getNetBurnOrIncomeReport = getNetBurnOrIncomeReport;
@@ -148,7 +160,10 @@ exports.getNetBurnOrIncomeForSelectedRange = (0, toolkit_1.createSelector)((stat
148
160
  selectedForecast?.id != null &&
149
161
  (0, exports.getNetBurnOrIncomeReportFetchState)(selectedForecast.id, netBurnOrIncomeWithForecastState).fetchState === 'Completed'
150
162
  ? getNetBurnOrIncomeWithForecastOnDataAvailableDateRange(noFilter, selectedForecast?.id, accountState, accountGroupState, sectionAccountsViewState, forecastListState, netBurnOrIncomeWithForecastState, forecastState)
151
- : (0, exports.getNetBurnOrIncomeReport)(accountState, accountGroupState, sectionAccountsViewState, netBurnOrIncomeWithForecastState, forecastState, forecastListState, noFilter, selectedForecast?.id);
163
+ : (0, exports.getNetBurnOrIncomeReport)(accountState, accountGroupState, sectionAccountsViewState, netBurnOrIncomeWithForecastState, forecastState, forecastListState, noFilter, selectedForecast?.id,
164
+ // Detail selectors read the custom slot when the detail is in custom
165
+ // mode; the dashboard's last-periods selector does not.
166
+ netBurnOrIncomeWithForecastState.uiState.customTimeframe != null);
152
167
  });
153
168
  exports.getNetBurnOrIncomeForHighlightedRange = (0, toolkit_1.createSelector)((state) => state.accountState, (state) => state.accountGroupState, (state) => state.sectionAccountsViewState, (state) => state.netBurnOrIncomeState, (state) => state.forecastState, (state) => state.forecastListState, (accountState, accountGroupState, sectionAccountsViewState, netBurnOrIncomeWithForecastState, forecastState, forecastListState) => {
154
169
  const { timeframe, highlightedCOABalancesRange, selectedAdditionalBalances, maxNumOfPeriodsToHighlight, selectedForecast, isForecastModeOn, } = netBurnOrIncomeWithForecastState.uiState;
@@ -158,7 +173,10 @@ exports.getNetBurnOrIncomeForHighlightedRange = (0, toolkit_1.createSelector)((s
158
173
  selectedForecast?.id != null &&
159
174
  (0, exports.getNetBurnOrIncomeReportFetchState)(selectedForecast.id, netBurnOrIncomeWithForecastState).fetchState === 'Completed'
160
175
  ? getNetBurnOrIncomeWithForecastOnDataAvailableDateRange(filter, selectedForecast?.id, accountState, accountGroupState, sectionAccountsViewState, forecastListState, netBurnOrIncomeWithForecastState, forecastState)
161
- : (0, exports.getNetBurnOrIncomeReport)(accountState, accountGroupState, sectionAccountsViewState, netBurnOrIncomeWithForecastState, forecastState, forecastListState, filter, selectedForecast?.id);
176
+ : (0, exports.getNetBurnOrIncomeReport)(accountState, accountGroupState, sectionAccountsViewState, netBurnOrIncomeWithForecastState, forecastState, forecastListState, filter, selectedForecast?.id,
177
+ // Detail selectors read the custom slot when the detail is in custom
178
+ // mode; the dashboard's last-periods selector does not.
179
+ netBurnOrIncomeWithForecastState.uiState.customTimeframe != null);
162
180
  });
163
181
  const getNetBurnOrIncomeReportFetchState = (forecastId, netBurnOrIncomeState) => {
164
182
  const netBurnOrIncome = (0, netBurnOrIncomeReducer_1.getState)(netBurnOrIncomeState, forecastId != null, forecastId);
@@ -20,6 +20,14 @@ export interface NetBurnOrIncomeState extends Report {
20
20
  insights: InsightSummary[];
21
21
  runwayAndAverages: RunwayAndAverages;
22
22
  cogs?: COABalanceGroupedByPeriod;
23
+ customCogs?: COABalanceGroupedByPeriod;
24
+ customExpenses?: COABalanceGroupedByPeriod;
25
+ customFetchState?: {
26
+ month: FetchStateAndError;
27
+ quarter: FetchStateAndError;
28
+ year: FetchStateAndError;
29
+ };
30
+ customIncome?: COABalanceGroupedByPeriod;
23
31
  expenses?: COABalanceGroupedByPeriod;
24
32
  forecastId?: ID;
25
33
  income?: COABalanceGroupedByPeriod;
@@ -9,6 +9,7 @@ export declare const fetchOpExWithForecastEpic: (actions$: ActionsObservable<Act
9
9
  error: import("../../zeniAPIStatus").ZeniAPIStatus<Record<string, unknown>>;
10
10
  forecastId: string | undefined;
11
11
  timeframe: "month" | "year" | "quarter";
12
+ isCustomDateRange: boolean;
12
13
  };
13
14
  type: "operatingExpenses/updateOpExFailureForTimeframe";
14
15
  }[]>;
@@ -5,12 +5,12 @@ const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const opExReducer_1 = require("./opExReducer");
7
7
  const fetchOpExEpic = (actions$, state) => actions$.pipe((0, operators_1.filter)(opExReducer_1.fetchOpEx.match), (0, operators_1.switchMap)((action) => {
8
- const { cacheOverride, forecastId } = action.payload;
8
+ const { cacheOverride, endDate, forecastId, startDate } = action.payload;
9
9
  if (cacheOverride === true) {
10
10
  return (0, rxjs_1.from)([
11
- (0, opExReducer_1.fetchOpExReportForTimeframe)('month', forecastId),
12
- (0, opExReducer_1.fetchOpExReportForTimeframe)('quarter', forecastId),
13
- (0, opExReducer_1.fetchOpExReportForTimeframe)('year', forecastId),
11
+ (0, opExReducer_1.fetchOpExReportForTimeframe)('month', forecastId, true, false, startDate, endDate),
12
+ (0, opExReducer_1.fetchOpExReportForTimeframe)('quarter', forecastId, true, false, startDate, endDate),
13
+ (0, opExReducer_1.fetchOpExReportForTimeframe)('year', forecastId, true, false, startDate, endDate),
14
14
  ]);
15
15
  }
16
16
  else {
@@ -19,15 +19,15 @@ const fetchOpExEpic = (actions$, state) => actions$.pipe((0, operators_1.filter)
19
19
  const timeframeFetchState = opExState.fetchState;
20
20
  if (timeframeFetchState['month'].fetchState !== 'In-Progress' &&
21
21
  timeframeFetchState['month'].fetchState !== 'Completed') {
22
- fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('month', forecastId));
22
+ fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('month', forecastId, true, false, startDate, endDate));
23
23
  }
24
24
  if (timeframeFetchState['quarter'].fetchState !== 'In-Progress' &&
25
25
  timeframeFetchState['quarter'].fetchState !== 'Completed') {
26
- fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('quarter', forecastId));
26
+ fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('quarter', forecastId, true, false, startDate, endDate));
27
27
  }
28
28
  if (timeframeFetchState['year'].fetchState !== 'In-Progress' &&
29
29
  timeframeFetchState['year'].fetchState !== 'Completed') {
30
- fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('year', forecastId));
30
+ fetchActions.push((0, opExReducer_1.fetchOpExReportForTimeframe)('year', forecastId, true, false, startDate, endDate));
31
31
  }
32
32
  return (0, rxjs_1.from)(fetchActions);
33
33
  }
@@ -7,5 +7,6 @@ import { RootState } from '../../rootStateTypes';
7
7
  import { ZeniAPI } from '../../zeniAPI';
8
8
  import { fetchOpExReportForTimeframe, updateOpExFailureForTimeframe, updateOpExForTimeframe, updateOpExThisPeriod } from './opExReducer';
9
9
  export type ActionType = ReturnType<typeof fetchOpExReportForTimeframe> | ReturnType<typeof updateOpExForTimeframe> | ReturnType<typeof updateSectionAccountsView> | ReturnType<typeof updateOpExThisPeriod> | ReturnType<typeof updateOpExFailureForTimeframe> | ReturnType<typeof updateForecast>;
10
- export declare const reportIdUniqueKey: (forecastId?: ID) => "operating_expenses" | `operating_expenses+${string}`;
10
+ export declare const CUSTOM_DATE_RANGE_SECTION_MARKER: ID;
11
+ export declare const reportIdUniqueKey: (forecastId?: ID, isCustomDateRange?: boolean) => "operating_expenses" | `operating_expenses+${string}`;
11
12
  export declare const fetchOpExReportForTimeframeEpic: (actions$: ActionsObservable<ActionType>, state: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.fetchOpExReportForTimeframeEpic = exports.reportIdUniqueKey = void 0;
3
+ exports.fetchOpExReportForTimeframeEpic = exports.reportIdUniqueKey = exports.CUSTOM_DATE_RANGE_SECTION_MARKER = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const forecastReducer_1 = require("../../entity/forecast/forecastReducer");
@@ -8,9 +8,15 @@ const sectionAccountsViewReducer_1 = require("../../entity/sectionAccountsView/s
8
8
  const responsePayload_1 = require("../../responsePayload");
9
9
  const reportsHelpers_1 = require("../common/reportsHelpers");
10
10
  const opExReducer_1 = require("./opExReducer");
11
- const reportIdUniqueKey = (forecastId) => forecastId != null
12
- ? `operating_expenses+${forecastId}`
13
- : 'operating_expenses';
11
+ // Reserved forecast-slot marker so custom-date section-accounts data lives under
12
+ // its own key (operating_expenses+<marker>) and a default fetch can never
13
+ // overwrite it. Real forecast ids are UUIDs, so this never collides.
14
+ exports.CUSTOM_DATE_RANGE_SECTION_MARKER = '__custom_date_range__';
15
+ const reportIdUniqueKey = (forecastId, isCustomDateRange) => isCustomDateRange === true
16
+ ? `operating_expenses+${exports.CUSTOM_DATE_RANGE_SECTION_MARKER}`
17
+ : forecastId != null
18
+ ? `operating_expenses+${forecastId}`
19
+ : 'operating_expenses';
14
20
  exports.reportIdUniqueKey = reportIdUniqueKey;
15
21
  const fetchOpExReportForTimeframeEpic = (actions$, state, zeniAPI) => actions$.pipe((0, operators_1.filter)(opExReducer_1.fetchOpExReportForTimeframe.match), (0, operators_1.mergeMap)((action) => {
16
22
  const queryValue = {
@@ -22,16 +28,23 @@ const fetchOpExReportForTimeframeEpic = (actions$, state, zeniAPI) => actions$.p
22
28
  queryValue.forecast_id = action.payload.forecastId;
23
29
  queryValue.is_forecast_vs_actual = true;
24
30
  }
31
+ if (action.payload.startDate != null && action.payload.endDate != null) {
32
+ queryValue.custom_start_date = action.payload.startDate;
33
+ queryValue.custom_end_date = action.payload.endDate;
34
+ }
25
35
  return zeniAPI
26
36
  .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/2.0/reports/operating_expenses?query=${encodeURIComponent(JSON.stringify(queryValue))}`)
27
37
  .pipe((0, operators_1.mergeMap)((response) => {
28
38
  if (response.data != null && (0, responsePayload_1.isSuccessResponse)(response)) {
29
39
  const actions = [];
30
- actions.push((0, sectionAccountsViewReducer_1.updateSectionAccountsView)(action.payload.timeframe, 'expenses', (0, exports.reportIdUniqueKey)(action.payload.forecastId), response.data.report.expenses, response.data.report.accounts, response.data.report.account_groups, response.data.report.currency));
40
+ actions.push((0, sectionAccountsViewReducer_1.updateSectionAccountsView)(action.payload.timeframe, 'expenses', (0, exports.reportIdUniqueKey)(action.payload.forecastId, action.payload.startDate != null &&
41
+ action.payload.endDate != null), response.data.report.expenses, response.data.report.accounts, response.data.report.account_groups, response.data.report.currency));
31
42
  actions.push((0, opExReducer_1.updateOpExForTimeframe)({
32
43
  timeframe: action.payload.timeframe,
33
44
  forecastId: action.payload.forecastId,
34
45
  report: response.data,
46
+ isCustomDateRange: action.payload.startDate != null &&
47
+ action.payload.endDate != null,
35
48
  }));
36
49
  if (action.payload.forecastId == null &&
37
50
  action.payload.timeframe === 'month') {
@@ -46,8 +59,10 @@ const fetchOpExReportForTimeframeEpic = (actions$, state, zeniAPI) => actions$.p
46
59
  return (0, rxjs_1.from)(actions);
47
60
  }
48
61
  else {
49
- return (0, rxjs_1.of)((0, opExReducer_1.updateOpExFailureForTimeframe)(response.status, action.payload.forecastId, action.payload.timeframe));
62
+ return (0, rxjs_1.of)((0, opExReducer_1.updateOpExFailureForTimeframe)(response.status, action.payload.forecastId, action.payload.timeframe, action.payload.startDate != null &&
63
+ action.payload.endDate != null));
50
64
  }
51
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, opExReducer_1.updateOpExFailureForTimeframe)((0, responsePayload_1.createZeniAPIStatus)('Unexpected error', 'OpEx REST API call errored out' + JSON.stringify(error)), action.payload.forecastId, action.payload.timeframe))));
65
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, opExReducer_1.updateOpExFailureForTimeframe)((0, responsePayload_1.createZeniAPIStatus)('Unexpected error', 'OpEx REST API call errored out' + JSON.stringify(error)), action.payload.forecastId, action.payload.timeframe, action.payload.startDate != null &&
66
+ action.payload.endDate != null))));
52
67
  }));
53
68
  exports.fetchOpExReportForTimeframeEpic = fetchOpExReportForTimeframeEpic;
@@ -10,26 +10,35 @@ export declare const defaultPeriods: {
10
10
  };
11
11
  export declare const initialOpExState: OpExState;
12
12
  export declare const initialState: OpExWithForecastState;
13
- export declare const fetchOpEx: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[fetchFullReport?: any, forecastId?: string | undefined, cacheOverride?: any], {
13
+ export declare const fetchOpEx: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[fetchFullReport?: any, forecastId?: string | undefined, cacheOverride?: any, startDate?: string | undefined, endDate?: string | undefined], {
14
14
  fetchFullReport: any;
15
15
  forecastId: string | undefined;
16
16
  cacheOverride: any;
17
- }, "operatingExpenses/fetchOpEx", never, never>, fetchOpExReportForTimeframe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[timeframe: "month" | "year" | "quarter", forecastId?: string | undefined, fetchFullReport?: boolean | undefined, cacheOverride?: boolean | undefined], {
17
+ startDate: string | undefined;
18
+ endDate: string | undefined;
19
+ }, "operatingExpenses/fetchOpEx", never, never>, fetchOpExReportForTimeframe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[timeframe: "month" | "year" | "quarter", forecastId?: string | undefined, fetchFullReport?: boolean | undefined, cacheOverride?: boolean | undefined, startDate?: string | undefined, endDate?: string | undefined], {
18
20
  forecastId: string | undefined;
19
21
  timeframe: "month" | "year" | "quarter";
20
22
  fetchFullReport: boolean;
21
23
  cacheOverride: boolean;
24
+ startDate: string | undefined;
25
+ endDate: string | undefined;
22
26
  }, "operatingExpenses/fetchOpExReportForTimeframe", never, never>, updateOpExForTimeframe: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
23
27
  report: ZeniReportData<OpExReportPayload>;
24
28
  timeframe: "month" | "quarter" | "year";
25
29
  forecastId?: string;
26
- }, "operatingExpenses/updateOpExForTimeframe">, updateOpExFailureForTimeframe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[error: ZeniAPIStatus<Record<string, unknown>>, forecastId: string | undefined, timeframe: "month" | "year" | "quarter"], {
30
+ isCustomDateRange?: boolean;
31
+ }, "operatingExpenses/updateOpExForTimeframe">, updateOpExFailureForTimeframe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[error: ZeniAPIStatus<Record<string, unknown>>, forecastId: string | undefined, timeframe: "month" | "year" | "quarter", isCustomDateRange?: boolean | undefined], {
27
32
  error: ZeniAPIStatus<Record<string, unknown>>;
28
33
  forecastId: string | undefined;
29
34
  timeframe: "month" | "year" | "quarter";
35
+ isCustomDateRange: boolean;
30
36
  }, "operatingExpenses/updateOpExFailureForTimeframe", never, never>, updateOpExCOABalancesRange: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
31
37
  selectedCOABalancesRange: COABalancesRange;
38
+ customEndDate?: string;
39
+ customStartDate?: string;
32
40
  highlightedCOABalancesRange?: COABalancesRangeWithThisPeriod;
41
+ isCustomDateRange?: boolean;
33
42
  }, "operatingExpenses/updateOpExCOABalancesRange">, updateOpExAdditionalBalancesSelection: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
34
43
  additionalBalances: COABalanceType[];
35
44
  isCompareModeOn: boolean;