@zeniai/client-epic-state 5.2.79 → 5.2.80

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 (21) hide show
  1. package/lib/entity/invoicing/dunningCase/dunningCasePayload.d.ts +2 -0
  2. package/lib/entity/invoicing/dunningCase/dunningCasePayload.js +1 -0
  3. package/lib/entity/invoicing/dunningCase/dunningCaseState.d.ts +2 -0
  4. package/lib/esm/entity/invoicing/dunningCase/dunningCasePayload.js +1 -0
  5. package/lib/esm/view/invoicing/invoicingDunningCaseDetailView/fetchInvoicingDunningCaseDetailPageEpic.js +6 -0
  6. package/lib/esm/view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewSelector.js +4 -1
  7. package/lib/esm/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListPageEpic.js +7 -0
  8. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -1
  9. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +3 -0
  10. package/lib/index.d.ts +1 -1
  11. package/lib/view/invoicing/invoicingDunningCaseDetailView/fetchInvoicingDunningCaseDetailPageEpic.d.ts +2 -1
  12. package/lib/view/invoicing/invoicingDunningCaseDetailView/fetchInvoicingDunningCaseDetailPageEpic.js +6 -0
  13. package/lib/view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewSelector.d.ts +3 -0
  14. package/lib/view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewSelector.js +4 -1
  15. package/lib/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListPageEpic.d.ts +2 -1
  16. package/lib/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListPageEpic.js +7 -0
  17. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.d.ts +18 -2
  18. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +25 -2
  19. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -2
  20. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +3 -0
  21. package/package.json +1 -1
@@ -21,6 +21,8 @@ export interface InvoicingDunningCasePayload {
21
21
  next_retry?: string;
22
22
  paused_reason?: string;
23
23
  paused_until?: string;
24
+ /** The dunning schedule step a retry runs next. */
25
+ schedule_step?: number | null;
24
26
  subscription_id?: string;
25
27
  }
26
28
  export declare const mapInvoicingDunningCasePayloadToState: (payload: InvoicingDunningCasePayload) => InvoicingDunningCase;
@@ -30,6 +30,7 @@ const mapInvoicingDunningCasePayloadToState = (payload) => {
30
30
  nextRetry: payload.next_retry != null ? (0, zeniDayJS_1.date)(payload.next_retry) : undefined,
31
31
  pausedReason: payload.paused_reason,
32
32
  pausedUntil: payload.paused_until != null ? (0, zeniDayJS_1.date)(payload.paused_until) : undefined,
33
+ scheduleStep: payload.schedule_step ?? undefined,
33
34
  subscriptionID: payload.subscription_id,
34
35
  };
35
36
  };
@@ -22,6 +22,8 @@ export interface InvoicingDunningCase {
22
22
  nextRetry?: ZeniDate;
23
23
  pausedReason?: string;
24
24
  pausedUntil?: ZeniDate;
25
+ /** The dunning schedule step a retry runs next. */
26
+ scheduleStep?: number;
25
27
  subscriptionID?: ID;
26
28
  }
27
29
  export interface InvoicingDunningCaseState {
@@ -27,6 +27,7 @@ export const mapInvoicingDunningCasePayloadToState = (payload) => {
27
27
  nextRetry: payload.next_retry != null ? date(payload.next_retry) : undefined,
28
28
  pausedReason: payload.paused_reason,
29
29
  pausedUntil: payload.paused_until != null ? date(payload.paused_until) : undefined,
30
+ scheduleStep: payload.schedule_step ?? undefined,
30
31
  subscriptionID: payload.subscription_id,
31
32
  };
32
33
  };
@@ -1,5 +1,7 @@
1
1
  import { EMPTY, from } from 'rxjs';
2
2
  import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
3
+ import { fetchInvoicingSettings } from '../settingsView/settingsViewReducer';
4
+ import { getInvoicingSettingsFetchState } from '../settingsView/settingsViewSelector';
3
5
  import { fetchInvoicingDunningCaseDetail, fetchInvoicingDunningCaseDetailPage, fetchInvoicingDunningEmailPreviewPage, } from './invoicingDunningCaseDetailViewReducer';
4
6
  /**
5
7
  * Fetch unless the record is already loaded or in flight — or always when the
@@ -25,5 +27,9 @@ export const fetchInvoicingDunningCaseDetailPageEpic = (actions$, state$) => act
25
27
  pageActions.push(fetchInvoicingDunningCaseDetail({ id }));
26
28
  }
27
29
  pageActions.push(fetchInvoicingDunningEmailPreviewPage({ id, cacheOverride }));
30
+ // The current step is labelled from the settings schedule.
31
+ if (shouldFetch(getInvoicingSettingsFetchState(state), false)) {
32
+ pageActions.push(fetchInvoicingSettings());
33
+ }
28
34
  return pageActions.length > 0 ? from(pageActions) : EMPTY;
29
35
  }));
@@ -1,6 +1,8 @@
1
1
  import { getInvoicingDunningCaseById as getInvoicingDunningCaseByIdFromState } from '../../../entity/invoicing/dunningCase/dunningCaseSelector';
2
2
  import { getInvoiceById } from '../../../entity/invoicing/invoice/invoiceSelector';
3
3
  import { invoicingFieldHelpForGroup } from '../invoicingConfigView/invoicingConfigViewSelector';
4
+ import { toInvoicingDunningCaseStep, } from '../invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
5
+ import { getInvoicingSettings } from '../settingsView/settingsViewSelector';
4
6
  const EMAIL_PREVIEW_NOT_STARTED = {
5
7
  error: undefined,
6
8
  fetchState: 'Not-Started',
@@ -16,10 +18,11 @@ export const getInvoicingDunningCaseDetail = (state, invoicingDunningCaseID) =>
16
18
  : undefined,
17
19
  fieldHelp: invoicingFieldHelpForGroup(state, 'dunning'),
18
20
  actionState: state.invoicingDunningCaseDetailViewState.actionStateById[invoicingDunningCaseID] ?? { error: undefined, fetchState: 'Not-Started' },
19
- dunningCase: getInvoicingDunningCaseById(state, invoicingDunningCaseID),
21
+ dunningCase,
20
22
  emailPreview: id === invoicingDunningCaseID ? emailPreview : EMAIL_PREVIEW_NOT_STARTED,
21
23
  fetchState,
22
24
  error,
25
+ step: toInvoicingDunningCaseStep(dunningCase?.scheduleStep, getInvoicingSettings(state)?.dunning_schedule, state.invoicingConfigViewState.dunningScheduleActionOptions),
23
26
  version: 1.0,
24
27
  };
25
28
  };
@@ -1,6 +1,8 @@
1
1
  import { concat, from } from 'rxjs';
2
2
  import { filter, mergeMap } from 'rxjs/operators';
3
3
  import { getInvoicingListTab, invoicingListSourceTab, planInvoicingListTabFetch, } from '../../invoicingListTabCache';
4
+ import { fetchInvoicingSettings } from '../../settingsView/settingsViewReducer';
5
+ import { getInvoicingSettingsFetchState } from '../../settingsView/settingsViewSelector';
4
6
  import { fetchInvoicingDunningCaseCounts, fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, } from '../invoicingDunningCaseListViewReducer';
5
7
  /**
6
8
  * Fetch unless the endpoint is already loaded or in flight — or always when the
@@ -36,5 +38,10 @@ export const fetchInvoicingDunningCaseListPageEpic = (actions$, state$) => actio
36
38
  if (shouldFetch(state.countsFetchState, cacheOverride)) {
37
39
  pageActions.push(fetchInvoicingDunningCaseCounts());
38
40
  }
41
+ // The step column labels steps from the settings schedule; a search or
42
+ // sort change does not touch settings, so only a missing load fetches.
43
+ if (shouldFetch(getInvoicingSettingsFetchState(state$.value), false)) {
44
+ pageActions.push(fetchInvoicingSettings());
45
+ }
39
46
  return concat(from(pageActions));
40
47
  }));
@@ -3,12 +3,30 @@ import { getInvoicingDunningCasesByIds } from '../../../entity/invoicing/dunning
3
3
  import { getInvoicingListTab, invoicingListSourceTab, } from '../invoicingListTabCache';
4
4
  import { invoicingTabIdsFromConfig } from '../invoicingTabHelper';
5
5
  import { ALL_INVOICING_DUNNING_CASE_TAB_IDS, INVOICING_DUNNING_CASE_COLUMNS, } from './invoicingDunningCaseListViewState';
6
+ /**
7
+ * Join a case's `scheduleStep` with the tenant's dunning schedule and the
8
+ * config's action labels. The step alone is still shown when settings have not
9
+ * loaded or the schedule no longer has that step.
10
+ */
11
+ export const toInvoicingDunningCaseStep = (scheduleStep, schedule, actionOptions) => {
12
+ if (scheduleStep == null) {
13
+ return undefined;
14
+ }
15
+ const action = schedule?.find((entry) => entry.step === scheduleStep)?.action;
16
+ return {
17
+ actionName: action != null
18
+ ? actionOptions.find((option) => option.code === action)?.name
19
+ : undefined,
20
+ step: scheduleStep,
21
+ totalSteps: schedule != null && schedule.length > 0 ? schedule.length : undefined,
22
+ };
23
+ };
6
24
  /**
7
25
  * Memoized so the denormalized `dunningCases` array (and the wrapping view
8
26
  * object) keep referential identity until the dunning-case entity slice or the
9
27
  * list-view slice actually change.
10
28
  */
11
- export const getInvoicingDunningCaseListView = createSelector((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (state) => state.invoicingConfigViewState.dunningCaseStatusOptions, (dunningCaseState, listViewState, statusOptions) => {
29
+ export const getInvoicingDunningCaseListView = createSelector((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (state) => state.invoicingConfigViewState.dunningCaseStatusOptions, (state) => state.invoicingSettingsViewState.settings?.dunning_schedule, (state) => state.invoicingConfigViewState.dunningScheduleActionOptions, (dunningCaseState, listViewState, statusOptions, schedule, actionOptions) => {
12
30
  const { activeTab } = listViewState;
13
31
  const tab = getInvoicingListTab(listViewState.byTab, invoicingListSourceTab(activeTab));
14
32
  const dunningCases = getInvoicingDunningCasesByIds(dunningCaseState, tab.ids);
@@ -28,6 +46,10 @@ export const getInvoicingDunningCaseListView = createSelector((state) => state.i
28
46
  statusOptions,
29
47
  }),
30
48
  sort: listViewState.sort,
49
+ stepById: Object.fromEntries(dunningCases.flatMap((dunningCase) => {
50
+ const step = toInvoicingDunningCaseStep(dunningCase.scheduleStep, schedule, actionOptions);
51
+ return step != null ? [[dunningCase.id, step]] : [];
52
+ })),
31
53
  version: 1.0,
32
54
  };
33
55
  });
@@ -3,6 +3,7 @@ export const ALL_INVOICING_DUNNING_CASE_SORT_KEYS = [
3
3
  'customer',
4
4
  'invoice',
5
5
  'attempts',
6
+ 'step',
6
7
  'next_retry',
7
8
  'days_past_due',
8
9
  'failureReason',
@@ -14,6 +15,8 @@ export const INVOICING_DUNNING_CASE_COLUMNS = [
14
15
  { key: 'customer', sortable: true },
15
16
  { key: 'invoice', sortable: true },
16
17
  { key: 'attempts', sortable: true },
18
+ // The list API does not sort on `schedule_step`.
19
+ { key: 'step', sortable: false },
17
20
  { key: 'next_retry', sortable: true },
18
21
  { key: 'days_past_due', sortable: true },
19
22
  { key: 'failureReason', sortable: false },
package/lib/index.d.ts CHANGED
@@ -1219,7 +1219,7 @@ export { fetchInvoicingDunningCaseCounts, fetchInvoicingDunningCaseList, fetchIn
1219
1219
  export { ALL_INVOICING_DUNNING_CASE_SORT_KEYS, ALL_INVOICING_DUNNING_CASE_TAB_IDS, INVOICING_DUNNING_CASE_COLUMNS, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState';
1220
1220
  export type { InvoicingDunningCaseColumnConfig, InvoicingDunningCaseFilters, InvoicingDunningCaseSortKey, InvoicingDunningCaseTabId, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState';
1221
1221
  export { getInvoicingDunningCaseListView } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
1222
- export type { InvoicingDunningCaseListView } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
1222
+ export type { InvoicingDunningCaseListView, InvoicingDunningCaseStep, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
1223
1223
  export { clearInvoicingDunningCaseDetailView, fetchInvoicingDunningCaseDetail, fetchInvoicingDunningCaseDetailPage, fetchInvoicingDunningEmailPreviewPage, invalidateInvoicingDunningEmailPreview, } from './view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewReducer';
1224
1224
  export { getInvoicingDunningCaseById, getInvoicingDunningCaseDetail, getInvoicingDunningEmailPreview, } from './view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewSelector';
1225
1225
  export type { InvoicingDunningCaseDetailView } from './view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewSelector';
@@ -1,8 +1,9 @@
1
1
  import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { Observable } from 'rxjs';
3
3
  import { RootState } from '../../../rootStateTypes';
4
+ import { fetchInvoicingSettings } from '../settingsView/settingsViewReducer';
4
5
  import { fetchInvoicingDunningCaseDetail, fetchInvoicingDunningCaseDetailPage, fetchInvoicingDunningEmailPreviewPage } from './invoicingDunningCaseDetailViewReducer';
5
- export type ActionType = ReturnType<typeof fetchInvoicingDunningCaseDetailPage> | ReturnType<typeof fetchInvoicingDunningCaseDetail> | ReturnType<typeof fetchInvoicingDunningEmailPreviewPage>;
6
+ export type ActionType = ReturnType<typeof fetchInvoicingDunningCaseDetailPage> | ReturnType<typeof fetchInvoicingDunningCaseDetail> | ReturnType<typeof fetchInvoicingDunningEmailPreviewPage> | ReturnType<typeof fetchInvoicingSettings>;
6
7
  /**
7
8
  * Orchestrates the dunning case detail page: the case record, plus a warm of
8
9
  * the email composer's preview so the dialog paints with content on first
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fetchInvoicingDunningCaseDetailPageEpic = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
+ const settingsViewReducer_1 = require("../settingsView/settingsViewReducer");
7
+ const settingsViewSelector_1 = require("../settingsView/settingsViewSelector");
6
8
  const invoicingDunningCaseDetailViewReducer_1 = require("./invoicingDunningCaseDetailViewReducer");
7
9
  /**
8
10
  * Fetch unless the record is already loaded or in flight — or always when the
@@ -28,6 +30,10 @@ const fetchInvoicingDunningCaseDetailPageEpic = (actions$, state$) => actions$.p
28
30
  pageActions.push((0, invoicingDunningCaseDetailViewReducer_1.fetchInvoicingDunningCaseDetail)({ id }));
29
31
  }
30
32
  pageActions.push((0, invoicingDunningCaseDetailViewReducer_1.fetchInvoicingDunningEmailPreviewPage)({ id, cacheOverride }));
33
+ // The current step is labelled from the settings schedule.
34
+ if (shouldFetch((0, settingsViewSelector_1.getInvoicingSettingsFetchState)(state), false)) {
35
+ pageActions.push((0, settingsViewReducer_1.fetchInvoicingSettings)());
36
+ }
31
37
  return pageActions.length > 0 ? (0, rxjs_1.from)(pageActions) : rxjs_1.EMPTY;
32
38
  }));
33
39
  exports.fetchInvoicingDunningCaseDetailPageEpic = fetchInvoicingDunningCaseDetailPageEpic;
@@ -4,6 +4,7 @@ import { InvoicingDunningCase } from '../../../entity/invoicing/dunningCase/dunn
4
4
  import { InvoicingInvoice } from '../../../entity/invoicing/invoice/invoiceState';
5
5
  import type { InvoicingFieldHelpByCode } from '../../../entity/invoicing/invoicingCommonPayload';
6
6
  import { RootState } from '../../../rootStateTypes';
7
+ import { InvoicingDunningCaseStep } from '../invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
7
8
  import { InvoicingDunningEmailPreviewState } from './invoicingDunningCaseDetailViewState';
8
9
  /**
9
10
  * Read-only view for the dunning case detail page: the dunning case entity + its
@@ -24,6 +25,8 @@ export interface InvoicingDunningCaseDetailView extends SelectorView {
24
25
  * selector rather than pairing this with the invoice detail view.
25
26
  */
26
27
  linkedInvoice?: InvoicingInvoice;
28
+ /** The schedule step a retry runs next; absent when the case has none. */
29
+ step?: InvoicingDunningCaseStep;
27
30
  }
28
31
  export declare const getInvoicingDunningCaseById: (state: RootState, id: string) => InvoicingDunningCase | undefined;
29
32
  export declare const getInvoicingDunningCaseDetail: (state: RootState, invoicingDunningCaseID: ID) => InvoicingDunningCaseDetailView;
@@ -4,6 +4,8 @@ exports.getInvoicingDunningEmailPreview = exports.getInvoicingDunningCaseDetail
4
4
  const dunningCaseSelector_1 = require("../../../entity/invoicing/dunningCase/dunningCaseSelector");
5
5
  const invoiceSelector_1 = require("../../../entity/invoicing/invoice/invoiceSelector");
6
6
  const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
7
+ const invoicingDunningCaseListViewSelector_1 = require("../invoicingDunningCaseListView/invoicingDunningCaseListViewSelector");
8
+ const settingsViewSelector_1 = require("../settingsView/settingsViewSelector");
7
9
  const EMAIL_PREVIEW_NOT_STARTED = {
8
10
  error: undefined,
9
11
  fetchState: 'Not-Started',
@@ -20,10 +22,11 @@ const getInvoicingDunningCaseDetail = (state, invoicingDunningCaseID) => {
20
22
  : undefined,
21
23
  fieldHelp: (0, invoicingConfigViewSelector_1.invoicingFieldHelpForGroup)(state, 'dunning'),
22
24
  actionState: state.invoicingDunningCaseDetailViewState.actionStateById[invoicingDunningCaseID] ?? { error: undefined, fetchState: 'Not-Started' },
23
- dunningCase: (0, exports.getInvoicingDunningCaseById)(state, invoicingDunningCaseID),
25
+ dunningCase,
24
26
  emailPreview: id === invoicingDunningCaseID ? emailPreview : EMAIL_PREVIEW_NOT_STARTED,
25
27
  fetchState,
26
28
  error,
29
+ step: (0, invoicingDunningCaseListViewSelector_1.toInvoicingDunningCaseStep)(dunningCase?.scheduleStep, (0, settingsViewSelector_1.getInvoicingSettings)(state)?.dunning_schedule, state.invoicingConfigViewState.dunningScheduleActionOptions),
27
30
  version: 1.0,
28
31
  };
29
32
  };
@@ -2,12 +2,13 @@ import { ActionsObservable, StateObservable } from 'redux-observable';
2
2
  import { Observable } from 'rxjs';
3
3
  import { updateInvoicingDunningCases } from '../../../../entity/invoicing/dunningCase/dunningCaseReducer';
4
4
  import { RootState } from '../../../../rootStateTypes';
5
+ import { fetchInvoicingSettings } from '../../settingsView/settingsViewReducer';
5
6
  import { fetchInvoicingDunningCaseCounts, fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, updateInvoicingDunningCaseCounts, updateInvoicingDunningCaseCountsFailure, updateInvoicingDunningCaseList, updateInvoicingDunningCaseListFailure } from '../invoicingDunningCaseListViewReducer';
6
7
  /**
7
8
  * Aggregate of every action emitted across the dunning-case list view epics.
8
9
  * Wired into the root action union for this view.
9
10
  */
10
- export type ActionType = ReturnType<typeof fetchInvoicingDunningCaseList> | ReturnType<typeof fetchInvoicingDunningCaseListPage> | ReturnType<typeof fetchInvoicingDunningCaseCounts> | ReturnType<typeof updateInvoicingDunningCaseList> | ReturnType<typeof updateInvoicingDunningCaseListFailure> | ReturnType<typeof updateInvoicingDunningCaseCounts> | ReturnType<typeof updateInvoicingDunningCaseCountsFailure> | ReturnType<typeof updateInvoicingDunningCases>;
11
+ export type ActionType = ReturnType<typeof fetchInvoicingDunningCaseList> | ReturnType<typeof fetchInvoicingDunningCaseListPage> | ReturnType<typeof fetchInvoicingDunningCaseCounts> | ReturnType<typeof updateInvoicingDunningCaseList> | ReturnType<typeof updateInvoicingDunningCaseListFailure> | ReturnType<typeof updateInvoicingDunningCaseCounts> | ReturnType<typeof updateInvoicingDunningCaseCountsFailure> | ReturnType<typeof updateInvoicingDunningCases> | ReturnType<typeof fetchInvoicingSettings>;
11
12
  /**
12
13
  * Orchestrates the dunning cases list page: on `fetchInvoicingDunningCaseListPage`,
13
14
  * fans out to the list and counts fetches, skipping any whose data is
@@ -4,6 +4,8 @@ exports.fetchInvoicingDunningCaseListPageEpic = void 0;
4
4
  const rxjs_1 = require("rxjs");
5
5
  const operators_1 = require("rxjs/operators");
6
6
  const invoicingListTabCache_1 = require("../../invoicingListTabCache");
7
+ const settingsViewReducer_1 = require("../../settingsView/settingsViewReducer");
8
+ const settingsViewSelector_1 = require("../../settingsView/settingsViewSelector");
7
9
  const invoicingDunningCaseListViewReducer_1 = require("../invoicingDunningCaseListViewReducer");
8
10
  /**
9
11
  * Fetch unless the endpoint is already loaded or in flight — or always when the
@@ -39,6 +41,11 @@ const fetchInvoicingDunningCaseListPageEpic = (actions$, state$) => actions$.pip
39
41
  if (shouldFetch(state.countsFetchState, cacheOverride)) {
40
42
  pageActions.push((0, invoicingDunningCaseListViewReducer_1.fetchInvoicingDunningCaseCounts)());
41
43
  }
44
+ // The step column labels steps from the settings schedule; a search or
45
+ // sort change does not touch settings, so only a missing load fetches.
46
+ if (shouldFetch((0, settingsViewSelector_1.getInvoicingSettingsFetchState)(state$.value), false)) {
47
+ pageActions.push((0, settingsViewReducer_1.fetchInvoicingSettings)());
48
+ }
42
49
  return (0, rxjs_1.concat)((0, rxjs_1.from)(pageActions));
43
50
  }));
44
51
  exports.fetchInvoicingDunningCaseListPageEpic = fetchInvoicingDunningCaseListPageEpic;
@@ -1,7 +1,7 @@
1
- import { FetchStateAndError } from '../../../commonStateTypes/common';
1
+ import { FetchStateAndError, ID } from '../../../commonStateTypes/common';
2
2
  import { SelectorView } from '../../../commonStateTypes/viewAndReport/viewAndReport';
3
3
  import { InvoicingDunningCase } from '../../../entity/invoicing/dunningCase/dunningCaseState';
4
- import { InvoicingListCounts, InvoicingNamedOption } from '../../../entity/invoicing/invoicingCommonPayload';
4
+ import { InvoicingDunningActionOption, InvoicingDunningScheduleStepPayload, InvoicingListCounts, InvoicingNamedOption } from '../../../entity/invoicing/invoicingCommonPayload';
5
5
  import { RootState } from '../../../rootStateTypes';
6
6
  import { InvoicingListSort } from '../invoicingApiHelper';
7
7
  import { InvoicingDunningCaseColumnConfig, InvoicingDunningCaseFilters, InvoicingDunningCaseTabId } from './invoicingDunningCaseListViewState';
@@ -14,9 +14,25 @@ export interface InvoicingDunningCaseListView extends SelectorView {
14
14
  filters: InvoicingDunningCaseFilters;
15
15
  /** Config status/type list; the page labels tabs and badges from it. */
16
16
  statusOptions: InvoicingNamedOption[];
17
+ /** Each listed case's schedule step, keyed by case id; absent when unknown. */
18
+ stepById: Record<ID, InvoicingDunningCaseStep>;
17
19
  tabIds: InvoicingDunningCaseTabId[];
18
20
  sort?: InvoicingListSort;
19
21
  }
22
+ /** The dunning schedule step a case's retry runs next, for display. */
23
+ export interface InvoicingDunningCaseStep {
24
+ step: number;
25
+ /** The configured step's action, e.g. "Email and retry". */
26
+ actionName?: string;
27
+ /** How many steps the tenant's schedule has, when settings are loaded. */
28
+ totalSteps?: number;
29
+ }
30
+ /**
31
+ * Join a case's `scheduleStep` with the tenant's dunning schedule and the
32
+ * config's action labels. The step alone is still shown when settings have not
33
+ * loaded or the schedule no longer has that step.
34
+ */
35
+ export declare const toInvoicingDunningCaseStep: (scheduleStep: number | undefined, schedule: InvoicingDunningScheduleStepPayload[] | undefined, actionOptions: InvoicingDunningActionOption[]) => InvoicingDunningCaseStep | undefined;
20
36
  /**
21
37
  * Memoized so the denormalized `dunningCases` array (and the wrapping view
22
38
  * object) keep referential identity until the dunning-case entity slice or the
@@ -1,17 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getInvoicingDunningCaseListView = void 0;
3
+ exports.getInvoicingDunningCaseListView = exports.toInvoicingDunningCaseStep = void 0;
4
4
  const toolkit_1 = require("@reduxjs/toolkit");
5
5
  const dunningCaseSelector_1 = require("../../../entity/invoicing/dunningCase/dunningCaseSelector");
6
6
  const invoicingListTabCache_1 = require("../invoicingListTabCache");
7
7
  const invoicingTabHelper_1 = require("../invoicingTabHelper");
8
8
  const invoicingDunningCaseListViewState_1 = require("./invoicingDunningCaseListViewState");
9
+ /**
10
+ * Join a case's `scheduleStep` with the tenant's dunning schedule and the
11
+ * config's action labels. The step alone is still shown when settings have not
12
+ * loaded or the schedule no longer has that step.
13
+ */
14
+ const toInvoicingDunningCaseStep = (scheduleStep, schedule, actionOptions) => {
15
+ if (scheduleStep == null) {
16
+ return undefined;
17
+ }
18
+ const action = schedule?.find((entry) => entry.step === scheduleStep)?.action;
19
+ return {
20
+ actionName: action != null
21
+ ? actionOptions.find((option) => option.code === action)?.name
22
+ : undefined,
23
+ step: scheduleStep,
24
+ totalSteps: schedule != null && schedule.length > 0 ? schedule.length : undefined,
25
+ };
26
+ };
27
+ exports.toInvoicingDunningCaseStep = toInvoicingDunningCaseStep;
9
28
  /**
10
29
  * Memoized so the denormalized `dunningCases` array (and the wrapping view
11
30
  * object) keep referential identity until the dunning-case entity slice or the
12
31
  * list-view slice actually change.
13
32
  */
14
- exports.getInvoicingDunningCaseListView = (0, toolkit_1.createSelector)((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (state) => state.invoicingConfigViewState.dunningCaseStatusOptions, (dunningCaseState, listViewState, statusOptions) => {
33
+ exports.getInvoicingDunningCaseListView = (0, toolkit_1.createSelector)((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (state) => state.invoicingConfigViewState.dunningCaseStatusOptions, (state) => state.invoicingSettingsViewState.settings?.dunning_schedule, (state) => state.invoicingConfigViewState.dunningScheduleActionOptions, (dunningCaseState, listViewState, statusOptions, schedule, actionOptions) => {
15
34
  const { activeTab } = listViewState;
16
35
  const tab = (0, invoicingListTabCache_1.getInvoicingListTab)(listViewState.byTab, (0, invoicingListTabCache_1.invoicingListSourceTab)(activeTab));
17
36
  const dunningCases = (0, dunningCaseSelector_1.getInvoicingDunningCasesByIds)(dunningCaseState, tab.ids);
@@ -31,6 +50,10 @@ exports.getInvoicingDunningCaseListView = (0, toolkit_1.createSelector)((state)
31
50
  statusOptions,
32
51
  }),
33
52
  sort: listViewState.sort,
53
+ stepById: Object.fromEntries(dunningCases.flatMap((dunningCase) => {
54
+ const step = (0, exports.toInvoicingDunningCaseStep)(dunningCase.scheduleStep, schedule, actionOptions);
55
+ return step != null ? [[dunningCase.id, step]] : [];
56
+ })),
34
57
  version: 1.0,
35
58
  };
36
59
  });
@@ -5,8 +5,8 @@ import { InvoicingListByTab } from '../invoicingListTabCache';
5
5
  export interface InvoicingDunningCaseFilters {
6
6
  search?: string;
7
7
  }
8
- export declare const ALL_INVOICING_DUNNING_CASE_SORT_KEYS: readonly ["customer", "invoice", "attempts", "next_retry", "days_past_due", "failureReason", "status", "amount"];
9
- export declare const toInvoicingDunningCaseSortKey: (v: string) => "status" | "invoice" | "amount" | "customer" | "attempts" | "next_retry" | "days_past_due" | "failureReason";
8
+ export declare const ALL_INVOICING_DUNNING_CASE_SORT_KEYS: readonly ["customer", "invoice", "attempts", "step", "next_retry", "days_past_due", "failureReason", "status", "amount"];
9
+ export declare const toInvoicingDunningCaseSortKey: (v: string) => "status" | "invoice" | "amount" | "customer" | "attempts" | "step" | "next_retry" | "days_past_due" | "failureReason";
10
10
  export type InvoicingDunningCaseSortKey = ReturnType<typeof toInvoicingDunningCaseSortKey>;
11
11
  /**
12
12
  * Structural column descriptor owned by CES so the dunning-list column set,
@@ -6,6 +6,7 @@ exports.ALL_INVOICING_DUNNING_CASE_SORT_KEYS = [
6
6
  'customer',
7
7
  'invoice',
8
8
  'attempts',
9
+ 'step',
9
10
  'next_retry',
10
11
  'days_past_due',
11
12
  'failureReason',
@@ -18,6 +19,8 @@ exports.INVOICING_DUNNING_CASE_COLUMNS = [
18
19
  { key: 'customer', sortable: true },
19
20
  { key: 'invoice', sortable: true },
20
21
  { key: 'attempts', sortable: true },
22
+ // The list API does not sort on `schedule_step`.
23
+ { key: 'step', sortable: false },
21
24
  { key: 'next_retry', sortable: true },
22
25
  { key: 'days_past_due', sortable: true },
23
26
  { key: 'failureReason', sortable: false },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.79",
3
+ "version": "5.2.80",
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",