@zeniai/client-epic-state 5.2.70 → 5.2.72
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.
- package/lib/entity/actualMatching/actualMatchingReducer.d.ts +3 -1
- package/lib/entity/actualMatching/actualMatchingReducer.js +11 -2
- package/lib/entity/aiCfo/aiCfoState.d.ts +2 -2
- package/lib/entity/billPay/billTransaction/billTransactionState.d.ts +2 -2
- package/lib/entity/chargeCardTransaction/chargeCardTransaction.d.ts +1 -1
- package/lib/entity/depositAccountTransaction/depositAccountTransaction.d.ts +1 -1
- package/lib/entity/invoicing/{product/productPayload.d.ts → invoicingCatalog/invoicingCatalogPayload.d.ts} +44 -6
- package/lib/entity/invoicing/{product/productPayload.js → invoicingCatalog/invoicingCatalogPayload.js} +50 -6
- package/lib/entity/invoicing/invoicingCatalog/invoicingCatalogReducer.d.ts +12 -0
- package/lib/entity/invoicing/{plan/planReducer.js → invoicingCatalog/invoicingCatalogReducer.js} +20 -21
- package/lib/entity/invoicing/{plan/planSelector.d.ts → invoicingCatalog/invoicingCatalogSelector.d.ts} +5 -6
- package/lib/entity/invoicing/{plan/planSelector.js → invoicingCatalog/invoicingCatalogSelector.js} +12 -12
- package/lib/entity/invoicing/{product/productState.d.ts → invoicingCatalog/invoicingCatalogState.d.ts} +42 -6
- package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +2 -0
- package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -0
- package/lib/entity/jeSchedules/jeSchedulesState.d.ts +2 -0
- package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +4 -4
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/epic.d.ts +4 -2
- package/lib/epic.js +5 -1
- package/lib/esm/entity/actualMatching/actualMatchingReducer.js +9 -1
- package/lib/esm/entity/invoicing/{product/productPayload.js → invoicingCatalog/invoicingCatalogPayload.js} +46 -3
- package/lib/esm/entity/invoicing/{plan/planReducer.js → invoicingCatalog/invoicingCatalogReducer.js} +19 -20
- package/lib/esm/entity/invoicing/{plan/planSelector.js → invoicingCatalog/invoicingCatalogSelector.js} +8 -8
- package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +2 -0
- package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/esm/epic.js +5 -1
- package/lib/esm/index.js +9 -12
- package/lib/esm/reducer.js +4 -7
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +4 -2
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +50 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +26 -13
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchTransactionsEpic.js +2 -23
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +89 -38
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +68 -62
- package/lib/esm/view/expenseAutomationView/types/actualMatchingViewState.js +15 -0
- package/lib/esm/view/invoicing/createInvoice/createInvoiceEpic.js +9 -1
- package/lib/esm/view/invoicing/createInvoice/createInvoiceSelector.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +5 -3
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/fetchInvoicingCatalogItemDetailEpic.js +2 -2
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogPlanActionEpic.js +2 -2
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogProductActionEpic.js +4 -4
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -7
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +2 -2
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +5 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +5 -1
- package/lib/esm/view/invoicing/invoiceList/invoiceListReducer.js +8 -1
- package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js +2 -2
- package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.js +2 -2
- package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +55 -22
- package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewState.js +1 -20
- package/lib/esm/view/invoicing/settingsView/settingsViewSelector.js +18 -9
- package/lib/esm/view/invoicing/settingsView/submitInvoicingBrandingFormEpic.js +11 -2
- package/lib/esm/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewEpic.js +31 -11
- package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewReducer.js +2 -1
- package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +4 -30
- package/lib/esm/view/spendManagement/commonSetup/epic/setup/resetKycKybEpic.js +37 -0
- package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +21 -1
- package/lib/esm/view/spendManagement/commonSetup/setupViewSelector.js +2 -1
- package/lib/index.d.ts +15 -19
- package/lib/index.js +65 -63
- package/lib/reducer.d.ts +1 -2
- package/lib/reducer.js +4 -7
- package/lib/rootStateTypes.d.ts +3 -5
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/fetchActualMatchingMatchEpic.js +3 -1
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.d.ts +10 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +54 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/matchAndReverseAccrualsEpic.js +24 -11
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/searchMatchTransactionsEpic.js +1 -22
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/actualMatchingPayload.d.ts +12 -1
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.d.ts +19 -8
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +90 -39
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +2 -2
- package/lib/view/expenseAutomationView/selectorTypes/actualMatchingViewSelectorTypes.d.ts +24 -10
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +7 -4
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +71 -62
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.d.ts +19 -4
- package/lib/view/expenseAutomationView/types/actualMatchingViewState.js +18 -1
- package/lib/view/invoicing/createInvoice/createInvoiceEpic.d.ts +3 -2
- package/lib/view/invoicing/createInvoice/createInvoiceEpic.js +8 -0
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.d.ts +2 -2
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.js +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +8 -9
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +5 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/fetchInvoicingCatalogItemDetailEpic.d.ts +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/fetchInvoicingCatalogItemDetailEpic.js +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.d.ts +3 -4
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogPlanActionEpic.d.ts +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogPlanActionEpic.js +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogProductActionEpic.d.ts +2 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/runInvoicingCatalogProductActionEpic.js +4 -4
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.d.ts +2 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -7
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +2 -2
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +6 -2
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +2 -2
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +5 -1
- package/lib/view/invoicing/invoiceList/invoiceListReducer.d.ts +3 -1
- package/lib/view/invoicing/invoiceList/invoiceListReducer.js +9 -2
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogListPageEpic.d.ts +2 -2
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.d.ts +2 -2
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js +2 -2
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.d.ts +2 -2
- package/lib/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogProductListEpic.js +2 -2
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewPayload.d.ts +3 -3
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.d.ts +33 -15
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +57 -23
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewState.d.ts +0 -15
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewState.js +0 -22
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +1 -1
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +1 -1
- package/lib/view/invoicing/settingsView/settingsViewSelector.d.ts +12 -3
- package/lib/view/invoicing/settingsView/settingsViewSelector.js +17 -8
- package/lib/view/invoicing/settingsView/submitInvoicingBrandingFormEpic.js +11 -2
- package/lib/view/onboardingView/customerView/epic/customerDetails/updateOnboardingCustomerViewEpic.js +31 -11
- package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.d.ts +3 -2
- package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.js +2 -1
- package/lib/view/onboardingView/customerView/onboardingCustomerViewState.d.ts +4 -0
- package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
- package/lib/view/spendManagement/billPay/billList/billListReducer.d.ts +5 -5
- package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
- package/lib/view/spendManagement/billPay/editBillView/editBillViewReducer.d.ts +2 -2
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.d.ts +1 -1
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +4 -30
- package/lib/view/spendManagement/commonSetup/epic/setup/resetKycKybEpic.d.ts +8 -0
- package/lib/view/spendManagement/commonSetup/epic/setup/resetKycKybEpic.js +41 -0
- package/lib/view/spendManagement/commonSetup/setupViewReducer.d.ts +1 -1
- package/lib/view/spendManagement/commonSetup/setupViewReducer.js +22 -2
- package/lib/view/spendManagement/commonSetup/setupViewSelector.d.ts +1 -0
- package/lib/view/spendManagement/commonSetup/setupViewSelector.js +2 -1
- package/lib/view/spendManagement/commonSetup/setupViewState.d.ts +1 -0
- package/lib/view/spendManagement/commonSetup/types/businessVerification.d.ts +2 -1
- package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.d.ts +2 -2
- package/lib/view/spendManagement/reimbursement/remiListView/remiListReducer.d.ts +5 -5
- package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +2 -2
- package/package.json +1 -1
- package/lib/entity/invoicing/plan/planPayload.d.ts +0 -40
- package/lib/entity/invoicing/plan/planPayload.js +0 -51
- package/lib/entity/invoicing/plan/planReducer.d.ts +0 -14
- package/lib/entity/invoicing/plan/planState.d.ts +0 -43
- package/lib/entity/invoicing/product/productReducer.d.ts +0 -9
- package/lib/entity/invoicing/product/productReducer.js +0 -50
- package/lib/entity/invoicing/product/productSelector.d.ts +0 -4
- package/lib/entity/invoicing/product/productSelector.js +0 -17
- package/lib/entity/invoicing/product/productState.js +0 -2
- package/lib/esm/entity/invoicing/plan/planPayload.js +0 -47
- package/lib/esm/entity/invoicing/product/productReducer.js +0 -43
- package/lib/esm/entity/invoicing/product/productSelector.js +0 -10
- package/lib/esm/entity/invoicing/product/productState.js +0 -1
- /package/lib/entity/invoicing/{plan/planState.js → invoicingCatalog/invoicingCatalogState.js} +0 -0
- /package/lib/esm/entity/invoicing/{plan/planState.js → invoicingCatalog/invoicingCatalogState.js} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createSelector } from '@reduxjs/toolkit';
|
|
1
2
|
import orderBy from 'lodash/orderBy';
|
|
2
3
|
import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
3
4
|
import { getActualMatchingMatchById } from '../../../entity/actualMatching/actualMatchingSelector';
|
|
@@ -5,7 +6,6 @@ import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeSched
|
|
|
5
6
|
import { getJEOneTimeAccrualByKey, } from '../../../entity/jeSchedules/jeSchedulesSelector';
|
|
6
7
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
7
8
|
import { date } from '../../../zeniDayJS';
|
|
8
|
-
import { actualMatchingTransactionLineKey, } from '../types/actualMatchingViewState';
|
|
9
9
|
export function getSelectedMonthYearForCurrentTenant(state) {
|
|
10
10
|
const tenantId = getCurrentTenant(state)?.tenantId;
|
|
11
11
|
if (tenantId == null) {
|
|
@@ -34,27 +34,6 @@ function toMatchModalAccrual(member) {
|
|
|
34
34
|
jeOneTimeAccrualKey: generateJEOneTimeAccrualKey(member.accrualId),
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
-
function uniqueMatchModalAccruals(pinned, searched) {
|
|
38
|
-
const byId = new Map();
|
|
39
|
-
pinned.forEach((row) => byId.set(row.accrualId, row));
|
|
40
|
-
searched.forEach((row) => {
|
|
41
|
-
if (!byId.has(row.accrualId)) {
|
|
42
|
-
byId.set(row.accrualId, row);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
return Array.from(byId.values());
|
|
46
|
-
}
|
|
47
|
-
function uniqueTransactionSearchResults(pinned, searched) {
|
|
48
|
-
const byKey = new Map();
|
|
49
|
-
pinned.forEach((row) => byKey.set(actualMatchingTransactionLineKey(row.transactionType, row.transactionIntegrationId, row.lineId), row));
|
|
50
|
-
searched.forEach((row) => {
|
|
51
|
-
const key = actualMatchingTransactionLineKey(row.transactionType, row.transactionIntegrationId, row.lineId);
|
|
52
|
-
if (!byKey.has(key)) {
|
|
53
|
-
byKey.set(key, row);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
return Array.from(byKey.values());
|
|
57
|
-
}
|
|
58
37
|
export function parseActualMatchingMatchId(matchId) {
|
|
59
38
|
const separator = matchId.indexOf(':');
|
|
60
39
|
if (separator <= 0 || separator === matchId.length - 1) {
|
|
@@ -115,13 +94,18 @@ function collectGroupedMembers(members) {
|
|
|
115
94
|
estimatedAmount: member.estimatedAmount,
|
|
116
95
|
jeDebitAccountName: member.jeDebitAccountName,
|
|
117
96
|
memo: member.memo,
|
|
97
|
+
reversalTransactionId: member.reversalTransactionId,
|
|
98
|
+
reversalTransactionIntegrationId: member.reversalTransactionIntegrationId,
|
|
118
99
|
serviceMonth: member.serviceMonth,
|
|
100
|
+
transactionId: member.transactionId,
|
|
101
|
+
transactionIntegrationId: member.transactionIntegrationId,
|
|
119
102
|
}));
|
|
120
103
|
}
|
|
121
104
|
function collectLeftoverMembers(leftovers) {
|
|
122
105
|
if (leftovers == null || leftovers.length === 0) {
|
|
123
106
|
return undefined;
|
|
124
107
|
}
|
|
108
|
+
// Leftover accruals did not post, so they have no journal-entry ids to open.
|
|
125
109
|
return leftovers.map((member) => ({
|
|
126
110
|
accrualId: member.accrualId,
|
|
127
111
|
estimatedAmount: member.estimatedAmount,
|
|
@@ -227,6 +211,7 @@ function emptyKpiSummary() {
|
|
|
227
211
|
actualsReceived: { count: 0, expectedCount: 0, vendorsPending: 0 },
|
|
228
212
|
autoReversed: { count: 0, percent: 0, clearedAmount: 0 },
|
|
229
213
|
pendingReview: { count: 0, amount: 0, estimatedMinutesToClear: 0 },
|
|
214
|
+
reversed: { count: 0 },
|
|
230
215
|
variance: { percent: 0, averagePercentPerMatch: 0, netAmount: 0 },
|
|
231
216
|
};
|
|
232
217
|
}
|
|
@@ -282,6 +267,7 @@ export function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
|
|
|
282
267
|
}
|
|
283
268
|
const autoReversed = kpiRows.filter((row) => row.kind === 'auto_reversed');
|
|
284
269
|
const pendingReview = kpiRows.filter((row) => row.kind === 'pending_review');
|
|
270
|
+
const reversed = kpiRows.filter((row) => isReversedMatchKind(row.kind));
|
|
285
271
|
const receivedCount = kpiRows.length;
|
|
286
272
|
const rowsWithActual = kpiRows.filter((row) => row.actualAmount?.amount != null);
|
|
287
273
|
const accruedTotal = rowsWithActual.reduce((sum, row) => sum + (row.accruedAmount?.amount ?? row.estimatedAmount.amount), 0);
|
|
@@ -307,6 +293,9 @@ export function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
|
|
|
307
293
|
amount: sumRowAmounts(pendingReview, displayCurrencyCode),
|
|
308
294
|
estimatedMinutesToClear: pendingReview.length * ESTIMATED_MINUTES_PER_PENDING_MATCH,
|
|
309
295
|
},
|
|
296
|
+
reversed: {
|
|
297
|
+
count: reversed.length,
|
|
298
|
+
},
|
|
310
299
|
variance: {
|
|
311
300
|
percent: accruedTotal === 0
|
|
312
301
|
? 0
|
|
@@ -319,23 +308,66 @@ export function buildActualMatchingKpiSummary(rows, displayCurrencyCode) {
|
|
|
319
308
|
},
|
|
320
309
|
};
|
|
321
310
|
}
|
|
322
|
-
|
|
323
|
-
const view = state.expenseAutomationActualMatchingViewState;
|
|
311
|
+
function toActualMatchingMatchView(match) {
|
|
324
312
|
return {
|
|
325
|
-
match
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
lastUndoResults: view.lastUndoResultsByMatchId?.[matchId],
|
|
313
|
+
...match,
|
|
314
|
+
members: match.members.map(toMatchModalAccrual),
|
|
315
|
+
leftovers: match.leftovers == null
|
|
316
|
+
? undefined
|
|
317
|
+
: match.leftovers.map(toMatchModalAccrual),
|
|
331
318
|
};
|
|
332
319
|
}
|
|
320
|
+
const matchViewSelectorById = new Map();
|
|
321
|
+
export function getExpenseAutomationActualMatchingMatchView(state, matchId) {
|
|
322
|
+
let selector = matchViewSelectorById.get(matchId);
|
|
323
|
+
if (selector == null) {
|
|
324
|
+
selector = createSelector([
|
|
325
|
+
(root) => root.expenseAutomationActualMatchingViewState
|
|
326
|
+
.detailFetchStateByMatchId[matchId] ?? NOT_STARTED,
|
|
327
|
+
(root) => root.expenseAutomationActualMatchingViewState.ignoreStatusByMatchId[matchId] ?? NOT_STARTED,
|
|
328
|
+
(root) => root.expenseAutomationActualMatchingViewState
|
|
329
|
+
.lastMatchResultsByMatchId?.[matchId],
|
|
330
|
+
(root) => root.expenseAutomationActualMatchingViewState
|
|
331
|
+
.lastUndoResultsByMatchId?.[matchId],
|
|
332
|
+
(root) => root.expenseAutomationActualMatchingViewState
|
|
333
|
+
.detailRefreshStatusByMatchId[matchId] ?? NOT_STARTED,
|
|
334
|
+
(root) => root.expenseAutomationActualMatchingViewState
|
|
335
|
+
.undoReversalStatusByMatchId[matchId] ?? NOT_STARTED,
|
|
336
|
+
(root) => getActualMatchingMatchById(root.actualMatchingState, matchId),
|
|
337
|
+
], (detailFetchState, ignoreStatus, lastMatchResults, lastUndoResults, refreshStatus, undoReversalStatus, match) => ({
|
|
338
|
+
detailFetchState,
|
|
339
|
+
ignoreStatus,
|
|
340
|
+
lastMatchResults,
|
|
341
|
+
lastUndoResults,
|
|
342
|
+
match: match == null ? undefined : toActualMatchingMatchView(match),
|
|
343
|
+
refreshStatus,
|
|
344
|
+
undoReversalStatus,
|
|
345
|
+
}));
|
|
346
|
+
matchViewSelectorById.set(matchId, selector);
|
|
347
|
+
}
|
|
348
|
+
return selector(state);
|
|
349
|
+
}
|
|
333
350
|
export function getCloseMatchAfterUndo(state) {
|
|
334
|
-
return state.expenseAutomationActualMatchingViewState
|
|
351
|
+
return state.expenseAutomationActualMatchingViewState
|
|
352
|
+
.closeMatchAfterUndoMatchIds[0];
|
|
353
|
+
}
|
|
354
|
+
export function getCloseMatchAfterUndoMatchId(state) {
|
|
355
|
+
return getCloseMatchAfterUndo(state);
|
|
356
|
+
}
|
|
357
|
+
export function getCloseMatchAfterIgnoreMatchId(state) {
|
|
358
|
+
return state.expenseAutomationActualMatchingViewState
|
|
359
|
+
.closeMatchAfterIgnoreMatchIds[0];
|
|
360
|
+
}
|
|
361
|
+
export function getActualMatchingMatchModalConfirmStatus(state, matchId) {
|
|
362
|
+
if (matchId != null && matchId !== '') {
|
|
363
|
+
return (state.expenseAutomationActualMatchingViewState.confirmStatusByMatchId[matchId] ?? NOT_STARTED);
|
|
364
|
+
}
|
|
365
|
+
return state.expenseAutomationActualMatchingViewState.matchModal
|
|
366
|
+
.confirmStatus;
|
|
335
367
|
}
|
|
336
368
|
export function getExpenseAutomationActualMatchingView(state) {
|
|
337
369
|
const { expenseAutomationActualMatchingViewState } = state;
|
|
338
|
-
const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, } = expenseAutomationActualMatchingViewState;
|
|
370
|
+
const { matchIdsByPeriod, fetchState, error, refreshStatus, uiState, matchModal, ignoreStatusByMatchId, undoReversalStatusByMatchId, } = expenseAutomationActualMatchingViewState;
|
|
339
371
|
const selectedPeriod = getSelectedMonthYearForCurrentTenant(state);
|
|
340
372
|
const monthYearPeriodId = selectedPeriod != null ? toMonthYearPeriodId(selectedPeriod) : undefined;
|
|
341
373
|
const matchIds = monthYearPeriodId != null ? matchIdsByPeriod[monthYearPeriodId] : undefined;
|
|
@@ -351,32 +383,6 @@ export function getExpenseAutomationActualMatchingView(state) {
|
|
|
351
383
|
const searchedAccruals = matchModal.accrualSearch.results
|
|
352
384
|
.map((key) => getJEOneTimeAccrualByKey(key, state.jeSchedulesState))
|
|
353
385
|
.filter((accrual) => accrual != null);
|
|
354
|
-
const openedMatch = matchModal.openedFromMatchId != null
|
|
355
|
-
? getActualMatchingMatchById(state.actualMatchingState, matchModal.openedFromMatchId)
|
|
356
|
-
: undefined;
|
|
357
|
-
const pinnedAccruals = [
|
|
358
|
-
...(openedMatch?.members ?? []),
|
|
359
|
-
...(openedMatch?.leftovers ?? []),
|
|
360
|
-
].map(toMatchModalAccrual);
|
|
361
|
-
const firstMember = openedMatch?.members[0];
|
|
362
|
-
const cleared = firstMember?.cleared;
|
|
363
|
-
const suggestion = firstMember?.matchSuggestion;
|
|
364
|
-
const stamp = cleared ?? suggestion;
|
|
365
|
-
const consumedLineIds = cleared?.consumedLineIds;
|
|
366
|
-
const prefill = openedMatch == null
|
|
367
|
-
? undefined
|
|
368
|
-
: {
|
|
369
|
-
selectedAccrualIds: [
|
|
370
|
-
...openedMatch.members.map((member) => member.accrualId),
|
|
371
|
-
...(openedMatch.leftovers ?? []).map((leftover) => leftover.accrualId),
|
|
372
|
-
],
|
|
373
|
-
actualAmount: openedMatch.actualAmount.amount,
|
|
374
|
-
matchedTransactionId: stamp?.matchedTransactionId,
|
|
375
|
-
matchedLineId: cleared == null ? suggestion?.matchedLineId : undefined,
|
|
376
|
-
...(consumedLineIds != null && consumedLineIds.length > 0
|
|
377
|
-
? { consumedLineIds }
|
|
378
|
-
: {}),
|
|
379
|
-
};
|
|
380
386
|
// `fetchState` is a flat slice field that survives a period switch. Until this
|
|
381
387
|
// month's ids land, leftover Completed/Error is the previous month. Report
|
|
382
388
|
// Not-Started so chrome matches Review's "cache slot missing" skeleton, not
|
|
@@ -394,16 +400,16 @@ export function getExpenseAutomationActualMatchingView(state) {
|
|
|
394
400
|
kpiSummary,
|
|
395
401
|
uiState,
|
|
396
402
|
refreshStatus,
|
|
403
|
+
ignoreStatusByMatchId,
|
|
404
|
+
undoReversalStatusByMatchId,
|
|
397
405
|
hasLoadedForSelectedPeriod: matchIds != null,
|
|
398
406
|
matchModal: {
|
|
399
407
|
isOpen: matchModal.isOpen,
|
|
400
|
-
openedFromMatchId: matchModal.openedFromMatchId,
|
|
401
|
-
prefill,
|
|
402
408
|
confirmStatus: matchModal.confirmStatus,
|
|
403
409
|
lastBatchResults: matchModal.lastBatchResults,
|
|
404
410
|
transactionSearch: {
|
|
405
411
|
query: matchModal.transactionSearch.query,
|
|
406
|
-
results:
|
|
412
|
+
results: matchModal.transactionSearch.results,
|
|
407
413
|
fetchState: {
|
|
408
414
|
fetchState: matchModal.transactionSearch.fetchState,
|
|
409
415
|
error: matchModal.transactionSearch.error,
|
|
@@ -413,7 +419,7 @@ export function getExpenseAutomationActualMatchingView(state) {
|
|
|
413
419
|
},
|
|
414
420
|
accrualSearch: {
|
|
415
421
|
query: matchModal.accrualSearch.query,
|
|
416
|
-
results:
|
|
422
|
+
results: searchedAccruals,
|
|
417
423
|
fetchState: {
|
|
418
424
|
fetchState: matchModal.accrualSearch.fetchState,
|
|
419
425
|
error: matchModal.accrualSearch.error,
|
|
@@ -13,6 +13,12 @@ const ACTUAL_MATCHING_SORT_KEYS = [
|
|
|
13
13
|
'variance',
|
|
14
14
|
];
|
|
15
15
|
export const toActualMatchingSortKey = (v) => stringToUnion(v, ACTUAL_MATCHING_SORT_KEYS);
|
|
16
|
+
const ACTUAL_MATCHING_STATUS_FILTERS = [
|
|
17
|
+
'all',
|
|
18
|
+
'pending_review',
|
|
19
|
+
'reversed',
|
|
20
|
+
];
|
|
21
|
+
export const toActualMatchingStatusFilter = (v) => stringToUnion(v, ACTUAL_MATCHING_STATUS_FILTERS);
|
|
16
22
|
export const MATCH_TRANSACTION_SEARCH_PAGE_SIZE = 50;
|
|
17
23
|
export const MATCH_ACCRUAL_SEARCH_LIMIT = 50;
|
|
18
24
|
export const MATCH_SEARCH_DEBOUNCE_MS = 300;
|
|
@@ -33,6 +39,15 @@ const UNDO_REVERSAL_RESULT_STATUSES = [
|
|
|
33
39
|
'error',
|
|
34
40
|
];
|
|
35
41
|
export const toUndoReversalResultStatus = (v) => stringToUnion(v, UNDO_REVERSAL_RESULT_STATUSES);
|
|
42
|
+
const ACTUAL_MATCHING_IGNORE_REASONS = [
|
|
43
|
+
'wrong_bill',
|
|
44
|
+
'wrong_period',
|
|
45
|
+
'amount_off',
|
|
46
|
+
'already_handled',
|
|
47
|
+
'other_ignore',
|
|
48
|
+
];
|
|
49
|
+
export const toActualMatchingIgnoreReasonType = (v) => stringToUnion(v, ACTUAL_MATCHING_IGNORE_REASONS);
|
|
50
|
+
export const ALL_ACTUAL_MATCHING_IGNORE_REASONS = ACTUAL_MATCHING_IGNORE_REASONS;
|
|
36
51
|
export function actualMatchingTransactionLineKey(transactionType, transactionIntegrationId, lineId) {
|
|
37
52
|
return `${transactionType}:${transactionIntegrationId}:${lineId}`;
|
|
38
53
|
}
|
|
@@ -6,7 +6,8 @@ import { updateInvoices } from '../../../entity/invoicing/invoice/invoiceReducer
|
|
|
6
6
|
import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiError';
|
|
7
7
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
8
8
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
9
|
-
import {
|
|
9
|
+
import { invalidateInvoicingCustomerDetail } from '../editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer';
|
|
10
|
+
import { addInvoiceToList, invalidateInvoiceListForCustomer, } from '../invoiceList/invoiceListReducer';
|
|
10
11
|
import { createInvoice, createInvoiceFailure, createInvoiceSuccess, } from './createInvoiceReducer';
|
|
11
12
|
export const createInvoiceEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(createInvoice.match), mergeMap((action) => {
|
|
12
13
|
const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/invoices`;
|
|
@@ -23,6 +24,13 @@ export const createInvoiceEpic = (actions$, _state$, zeniAPI) => actions$.pipe(f
|
|
|
23
24
|
id: response.data.id,
|
|
24
25
|
status: response.data.status,
|
|
25
26
|
}),
|
|
27
|
+
// The customer's page caches their invoices and totals.
|
|
28
|
+
invalidateInvoicingCustomerDetail({
|
|
29
|
+
id: response.data.customer_id,
|
|
30
|
+
}),
|
|
31
|
+
invalidateInvoiceListForCustomer({
|
|
32
|
+
customerId: response.data.customer_id,
|
|
33
|
+
}),
|
|
26
34
|
createInvoiceSuccess({ invoiceId: response.data.id }),
|
|
27
35
|
openSnackbar({
|
|
28
36
|
messageSection: 'invoicing_invoice_saved',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getAddressByAddressId } from '../../../entity/address/addressSelector';
|
|
2
|
-
import { invoicingPricePointDisplayAmount } from '../../../entity/invoicing/
|
|
2
|
+
import { invoicingPricePointDisplayAmount } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogSelector';
|
|
3
3
|
import { getInvoicingCatalogListView, getInvoicingCatalogPrices, } from '../invoicingCatalogListView/invoicingCatalogListViewSelector';
|
|
4
4
|
import { invoicingFieldHelpForGroup } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
5
|
import { getInvoicingCustomerListView } from '../invoicingCustomerListView/invoicingCustomerListViewSelector';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
2
|
import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
|
-
import {
|
|
3
|
+
import { getInvoicingCatalogItemById, getInvoicingCatalogItemsByIds, } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogSelector';
|
|
4
4
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
5
|
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
6
6
|
import { INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES, INVOICING_INCOME_ACCOUNT_MAPPING_SLOT, NO_INVOICING_ACCOUNT_HIERARCHY, NO_INVOICING_ACCOUNT_IDS, NO_INVOICING_CLASS_HIERARCHY, getInvoicingQboAccountOptions, getInvoicingQboView, invoicingQboAccountIdsForMappingSlot, isInvoicingAccountingPickerDataLoading, isInvoicingQboConnected, } from '../invoicingQboView/invoicingQboViewSelector';
|
|
@@ -36,7 +36,7 @@ const buildApplicableCatalogItemOptions = (plans) => {
|
|
|
36
36
|
* Kept referentially stable across unrelated dispatches; the form view filters
|
|
37
37
|
* out the item being edited (see `getInvoicingCatalogItemFormView`).
|
|
38
38
|
*/
|
|
39
|
-
export const getInvoicingApplicableCatalogItemOptions = createSelector((state) => state.
|
|
39
|
+
export const getInvoicingApplicableCatalogItemOptions = createSelector((state) => state.invoicingCatalogState, (state) => state.invoicingCatalogListViewState, (catalogState, listViewState) => buildApplicableCatalogItemOptions(getInvoicingCatalogItemsByIds(catalogState, [
|
|
40
40
|
...listViewState.planIds,
|
|
41
41
|
...listViewState.productIds,
|
|
42
42
|
])));
|
|
@@ -61,7 +61,9 @@ const getInvoicingCatalogIncomeAccountIds = createSelector([
|
|
|
61
61
|
: NO_INVOICING_ACCOUNT_IDS);
|
|
62
62
|
export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
63
63
|
const { editDraftById, error, fetchState, newItemDraft, savedItemId, savedKind, } = state.editInvoicingCatalogItemDetailViewState;
|
|
64
|
-
const plan = id != null
|
|
64
|
+
const plan = id != null
|
|
65
|
+
? getInvoicingCatalogItemById(state.invoicingCatalogState, id)
|
|
66
|
+
: undefined;
|
|
65
67
|
const kind = plan != null ? 'plan' : undefined;
|
|
66
68
|
// No entity fallback: the draft is the one source of form values, seeded from
|
|
67
69
|
// the record by `seedInvoicingCatalogItemFormDraftEpic` when the detail load
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, switchMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
3
|
+
import { updateInvoicingCatalogItems } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
5
5
|
import { fetchInvoicingCatalogItemDetail, updateInvoicingCatalogItemDetail, updateInvoicingCatalogItemDetailFailure, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
6
6
|
export const fetchInvoicingCatalogItemDetailEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchInvoicingCatalogItemDetail.match), switchMap((action) => {
|
|
@@ -9,7 +9,7 @@ export const fetchInvoicingCatalogItemDetailEpic = (actions$, _state$, zeniAPI)
|
|
|
9
9
|
return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
|
|
10
10
|
if (isSuccessResponse(response) && response.data != null) {
|
|
11
11
|
return [
|
|
12
|
-
|
|
12
|
+
updateInvoicingCatalogItems([response.data], 'merge'),
|
|
13
13
|
updateInvoicingCatalogItemDetail({ id: response.data.id, kind }),
|
|
14
14
|
];
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
3
|
+
import { updateInvoicingCatalogItems } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
5
5
|
import { runInvoicingCatalogPlanAction, runInvoicingCatalogPlanActionFailure, runInvoicingCatalogPlanActionSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
6
6
|
export const runInvoicingCatalogPlanActionEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(runInvoicingCatalogPlanAction.match), mergeMap((action) => {
|
|
@@ -12,7 +12,7 @@ export const runInvoicingCatalogPlanActionEpic = (actions$, _state$, zeniAPI) =>
|
|
|
12
12
|
.pipe(mergeMap((response) => {
|
|
13
13
|
if (isSuccessResponse(response) && response.data != null) {
|
|
14
14
|
return [
|
|
15
|
-
|
|
15
|
+
updateInvoicingCatalogItems([response.data], 'merge'),
|
|
16
16
|
runInvoicingCatalogPlanActionSuccess({ id }),
|
|
17
17
|
];
|
|
18
18
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { updateInvoicingProducts } from '../../../entity/invoicing/product/productReducer';
|
|
3
|
+
import { mergeInvoicingCatalogPricePoint } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
5
4
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
6
5
|
import { runInvoicingCatalogProductAction, runInvoicingCatalogProductActionFailure, runInvoicingCatalogProductActionSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
7
6
|
export const runInvoicingCatalogProductActionEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(runInvoicingCatalogProductAction.match), mergeMap((action) => {
|
|
@@ -16,9 +15,10 @@ export const runInvoicingCatalogProductActionEpic = (actions$, _state$, zeniAPI)
|
|
|
16
15
|
.pipe(mergeMap((response) => {
|
|
17
16
|
if (isSuccessResponse(response) && response.data != null) {
|
|
18
17
|
return [
|
|
19
|
-
updateInvoicingProducts([response.data], 'merge'),
|
|
20
18
|
...(parentItemId != null
|
|
21
|
-
? [
|
|
19
|
+
? [
|
|
20
|
+
mergeInvoicingCatalogPricePoint(parentItemId, response.data),
|
|
21
|
+
]
|
|
22
22
|
: []),
|
|
23
23
|
runInvoicingCatalogProductActionSuccess({ id: stateKey }),
|
|
24
24
|
];
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { forkJoin, from } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
4
|
-
import { updateInvoicingProducts } from '../../../entity/invoicing/product/productReducer';
|
|
3
|
+
import { mergeInvoicingCatalogPricePoint, updateInvoicingCatalogItems, } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
5
4
|
import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiError';
|
|
6
5
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
7
6
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
@@ -51,11 +50,8 @@ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actio
|
|
|
51
50
|
}
|
|
52
51
|
const savedProducts = productResponses.flatMap((productResponse) => productResponse.data != null ? [productResponse.data] : []);
|
|
53
52
|
const resultActions = [
|
|
54
|
-
|
|
55
|
-
...
|
|
56
|
-
? [updateInvoicingProducts(savedProducts, 'merge')]
|
|
57
|
-
: []),
|
|
58
|
-
...savedProducts.map((product) => mergeInvoicingPlanSubFamily(savedItem.id, product)),
|
|
53
|
+
updateInvoicingCatalogItems([savedItem], 'merge'),
|
|
54
|
+
...savedProducts.map((product) => mergeInvoicingCatalogPricePoint(savedItem.id, product)),
|
|
59
55
|
submitInvoicingCatalogItemFormSuccess({
|
|
60
56
|
itemId: savedItem.id,
|
|
61
57
|
kind: 'plan',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMPTY, of } from 'rxjs';
|
|
2
2
|
import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
3
|
+
import { getInvoicingCatalogItemById } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogSelector';
|
|
4
4
|
import { fetchInvoicingCatalogItemDetailPage, seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
5
5
|
import { entityToInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormHelper';
|
|
6
6
|
/**
|
|
@@ -34,7 +34,7 @@ export const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actio
|
|
|
34
34
|
}
|
|
35
35
|
// Nothing to seed from on a cold open; the detail response triggers this
|
|
36
36
|
// again once it lands.
|
|
37
|
-
const plan =
|
|
37
|
+
const plan = getInvoicingCatalogItemById(state.invoicingCatalogState, id);
|
|
38
38
|
if (plan == null) {
|
|
39
39
|
return EMPTY;
|
|
40
40
|
}
|
|
@@ -95,6 +95,10 @@ const editInvoicingCustomerDetailView = createSlice({
|
|
|
95
95
|
error: undefined,
|
|
96
96
|
};
|
|
97
97
|
},
|
|
98
|
+
// Makes the page epic refetch a record that changed server-side (e.g. a new subscription).
|
|
99
|
+
invalidateInvoicingCustomerDetail(draft, action) {
|
|
100
|
+
delete draft.recordStateById[action.payload.id];
|
|
101
|
+
},
|
|
98
102
|
fetchInvoicingCustomerDetail(draft, action) {
|
|
99
103
|
draft.recordStateById[action.payload.id] = {
|
|
100
104
|
fetchState: 'In-Progress',
|
|
@@ -198,5 +202,5 @@ const editInvoicingCustomerDetailView = createSlice({
|
|
|
198
202
|
});
|
|
199
203
|
},
|
|
200
204
|
});
|
|
201
|
-
export const { fetchInvoicingPaymentLinkEmailPreview, fetchInvoicingPaymentLinkEmailPreviewPage, updateInvoicingPaymentLinkEmailPreview, updateInvoicingPaymentLinkEmailPreviewFailure, addPromotionalCreditsFailure, addPromotionalCreditsSuccess, fetchInvoicingCustomerDetail, fetchInvoicingCustomerDetailPage, seedInvoicingCustomerFormDraft, updateInvoicingCustomerDetail, resetPromotionalCreditAction, submitAddPromotionalCredits, updateInvoicingCustomerDetailFailure, updateInvoicingCustomerFormDraft, submitInvoicingCustomerForm, submitInvoicingCustomerFormSuccess, submitInvoicingCustomerFormFailure, resetEditInvoicingCustomerDetailView, initializeInvoicingCustomerAddress, claimInvoicingCustomerBillingAddress, } = editInvoicingCustomerDetailView.actions;
|
|
205
|
+
export const { fetchInvoicingPaymentLinkEmailPreview, fetchInvoicingPaymentLinkEmailPreviewPage, updateInvoicingPaymentLinkEmailPreview, updateInvoicingPaymentLinkEmailPreviewFailure, addPromotionalCreditsFailure, addPromotionalCreditsSuccess, fetchInvoicingCustomerDetail, fetchInvoicingCustomerDetailPage, invalidateInvoicingCustomerDetail, seedInvoicingCustomerFormDraft, updateInvoicingCustomerDetail, resetPromotionalCreditAction, submitAddPromotionalCredits, updateInvoicingCustomerDetailFailure, updateInvoicingCustomerFormDraft, submitInvoicingCustomerForm, submitInvoicingCustomerFormSuccess, submitInvoicingCustomerFormFailure, resetEditInvoicingCustomerDetailView, initializeInvoicingCustomerAddress, claimInvoicingCustomerBillingAddress, } = editInvoicingCustomerDetailView.actions;
|
|
202
206
|
export default editInvoicingCustomerDetailView.reducer;
|
package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js
CHANGED
|
@@ -7,6 +7,8 @@ import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiE
|
|
|
7
7
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
8
8
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
9
9
|
import { resetNewAddressDataInLocalStore } from '../../addressView/addressViewReducer';
|
|
10
|
+
import { invalidateInvoicingCustomerDetail } from '../editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer';
|
|
11
|
+
import { invalidateInvoiceListForCustomer } from '../invoiceList/invoiceListReducer';
|
|
10
12
|
import { addInvoicingSubscriptionToList } from '../invoicingSubscriptionListView/invoicingSubscriptionListViewReducer';
|
|
11
13
|
import { localDataToSaveInvoicingSubscriptionPayload, } from './editInvoicingSubscriptionDetailViewPayload';
|
|
12
14
|
import { submitInvoicingSubscriptionForm, submitInvoicingSubscriptionFormFailure, submitInvoicingSubscriptionFormSuccess, syncInvoicingSubscriptionCoupons, } from './editInvoicingSubscriptionDetailViewReducer';
|
|
@@ -86,7 +88,9 @@ export const saveInvoicingSubscriptionEpic = (actions$, state$, zeniAPI) => acti
|
|
|
86
88
|
resultActions.push(addInvoicingSubscriptionToList({
|
|
87
89
|
id: saved.id,
|
|
88
90
|
status: saved.status,
|
|
89
|
-
})
|
|
91
|
+
}),
|
|
92
|
+
// The service may bill the first invoice on create.
|
|
93
|
+
invalidateInvoicingCustomerDetail({ id: saved.customer_id }), invalidateInvoiceListForCustomer({ customerId: saved.customer_id }));
|
|
90
94
|
}
|
|
91
95
|
resultActions.push(openSnackbar({
|
|
92
96
|
messageSection: 'invoicing_subscription_saved',
|
|
@@ -124,6 +124,13 @@ const invoiceList = createSlice({
|
|
|
124
124
|
draft.kpisFetchState.fetchState = 'Error';
|
|
125
125
|
draft.kpisFetchState.error = action.payload;
|
|
126
126
|
},
|
|
127
|
+
// Counts are fetched under the same customer filter, so they go stale with the tabs.
|
|
128
|
+
invalidateInvoiceListForCustomer(draft, action) {
|
|
129
|
+
if (draft.filters.customerId === action.payload.customerId) {
|
|
130
|
+
draft.invoiceByTab = makeInvoiceByTab();
|
|
131
|
+
draft.countsFetchState = { fetchState: 'Not-Started', error: undefined };
|
|
132
|
+
}
|
|
133
|
+
},
|
|
127
134
|
updateInvoiceListFilters(draft, action) {
|
|
128
135
|
draft.filters = action.payload;
|
|
129
136
|
},
|
|
@@ -166,5 +173,5 @@ const invoiceList = createSlice({
|
|
|
166
173
|
});
|
|
167
174
|
},
|
|
168
175
|
});
|
|
169
|
-
export const { fetchInvoiceList, fetchInvoiceListPage, updateInvoiceList, updateInvoiceListFailure, fetchInvoiceCounts, updateInvoiceCounts, updateInvoiceCountsFailure, fetchInvoiceKPIs, updateInvoiceKPIs, updateInvoiceKPIsFailure, updateInvoiceListFilters, setInvoiceActiveTab, addInvoiceToList, } = invoiceList.actions;
|
|
176
|
+
export const { fetchInvoiceList, fetchInvoiceListPage, updateInvoiceList, updateInvoiceListFailure, fetchInvoiceCounts, updateInvoiceCounts, updateInvoiceCountsFailure, fetchInvoiceKPIs, updateInvoiceKPIs, updateInvoiceKPIsFailure, updateInvoiceListFilters, setInvoiceActiveTab, addInvoiceToList, invalidateInvoiceListForCustomer, } = invoiceList.actions;
|
|
170
177
|
export default invoiceList.reducer;
|
package/lib/esm/view/invoicing/invoicingCatalogListView/epics/fetchInvoicingCatalogPlanListEpic.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, switchMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
3
|
+
import { updateInvoicingCatalogItems } from '../../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
5
|
import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../../invoicingApiHelper';
|
|
6
6
|
import { fetchInvoicingCatalogPlanList, updateInvoicingCatalogPlanList, updateInvoicingCatalogPlanListFailure, } from '../invoicingCatalogListViewReducer';
|
|
@@ -29,7 +29,7 @@ export const fetchInvoicingCatalogPlanListEpic = (actions$, _state$, zeniAPI) =>
|
|
|
29
29
|
if (isSuccessResponse(response)) {
|
|
30
30
|
const items = response.data?.items ?? [];
|
|
31
31
|
return [
|
|
32
|
-
|
|
32
|
+
updateInvoicingCatalogItems(items, 'merge'),
|
|
33
33
|
updateInvoicingCatalogPlanList({
|
|
34
34
|
ids: items.map((item) => item.id),
|
|
35
35
|
nextCursor: response.data?.next_cursor ?? null,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, switchMap } from 'rxjs/operators';
|
|
3
|
-
import {
|
|
3
|
+
import { updateInvoicingCatalogItems } from '../../../../entity/invoicing/invoicingCatalog/invoicingCatalogReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
5
|
import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../../invoicingApiHelper';
|
|
6
6
|
import { fetchInvoicingCatalogProductList, updateInvoicingCatalogProductList, updateInvoicingCatalogProductListFailure, } from '../invoicingCatalogListViewReducer';
|
|
@@ -29,7 +29,7 @@ export const fetchInvoicingCatalogProductListEpic = (actions$, _state$, zeniAPI)
|
|
|
29
29
|
if (isSuccessResponse(response)) {
|
|
30
30
|
const items = response.data?.items ?? [];
|
|
31
31
|
return [
|
|
32
|
-
|
|
32
|
+
updateInvoicingCatalogItems(items, 'merge'),
|
|
33
33
|
updateInvoicingCatalogProductList({
|
|
34
34
|
ids: items.map((item) => item.id),
|
|
35
35
|
nextCursor: response.data?.next_cursor ?? null,
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
|
-
import {
|
|
3
|
-
import { runningInvoicingActionId } from '../runningInvoicingActionId';
|
|
4
|
-
import { INVOICING_PRODUCT_COLUMNS, } from './invoicingCatalogListViewState';
|
|
2
|
+
import { getInvoicingCatalogItemsByIds, invoicingPricePointDisplayAmount, } from '../../../entity/invoicing/invoicingCatalog/invoicingCatalogSelector';
|
|
5
3
|
/**
|
|
6
4
|
* Flatten catalog items into the price rows the pickers render.
|
|
7
5
|
*
|
|
@@ -22,28 +20,63 @@ export const getInvoicingCatalogPrices = (items) => items.flatMap((item) => (ite
|
|
|
22
20
|
priceCode: subFamily.priceCode,
|
|
23
21
|
productCode: item.productCode,
|
|
24
22
|
})));
|
|
23
|
+
const lowestStartingTier = (tiers) => tiers.reduce((lowest, tier) => lowest == null || tier.startingUnit < lowest.startingUnit ? tier : lowest, undefined);
|
|
24
|
+
export const getInvoicingCatalogPlanRows = (items) => items.flatMap((item) => {
|
|
25
|
+
const pricePoints = item.subFamilies ?? [];
|
|
26
|
+
if (pricePoints.length === 0) {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
id: item.id,
|
|
30
|
+
item,
|
|
31
|
+
period: item.period,
|
|
32
|
+
periodUnit: item.periodUnit,
|
|
33
|
+
price: item.price,
|
|
34
|
+
productFamily: item.name,
|
|
35
|
+
status: item.status,
|
|
36
|
+
tierCount: item.tiers?.length ?? 0,
|
|
37
|
+
firstTier: lowestStartingTier(item.tiers ?? []),
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return pricePoints.map((pricePoint) => ({
|
|
42
|
+
id: pricePoint.id,
|
|
43
|
+
item,
|
|
44
|
+
period: pricePoint.period,
|
|
45
|
+
periodUnit: pricePoint.periodUnit,
|
|
46
|
+
planName: pricePoint.name,
|
|
47
|
+
price: invoicingPricePointDisplayAmount(pricePoint),
|
|
48
|
+
pricingModel: pricePoint.pricingModel,
|
|
49
|
+
productFamily: item.name,
|
|
50
|
+
status: pricePoint.status,
|
|
51
|
+
tierCount: pricePoint.tiers?.length ?? 0,
|
|
52
|
+
firstTier: lowestStartingTier(pricePoint.tiers ?? []),
|
|
53
|
+
}));
|
|
54
|
+
});
|
|
25
55
|
/**
|
|
26
56
|
* Bundled read view for the single catalog page (plans + products tabs).
|
|
27
57
|
* Memoized over the plan + product entity slices and the list-view slice so the
|
|
28
58
|
* denormalized arrays keep referential identity. The base `fetchState`/`error`
|
|
29
59
|
* track the plan list; the product list has its own `productFetchState`.
|
|
30
60
|
*/
|
|
31
|
-
export const getInvoicingCatalogListView = createSelector((state) => state.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
61
|
+
export const getInvoicingCatalogListView = createSelector((state) => state.invoicingCatalogState, (state) => state.invoicingCatalogListViewState, (catalogState, listViewState) => {
|
|
62
|
+
const plans = getInvoicingCatalogItemsByIds(catalogState, listViewState.planIds);
|
|
63
|
+
const products = getInvoicingCatalogItemsByIds(catalogState, listViewState.productIds);
|
|
64
|
+
return {
|
|
65
|
+
planRows: getInvoicingCatalogPlanRows(plans),
|
|
66
|
+
plans,
|
|
67
|
+
planSort: listViewState.planSort,
|
|
68
|
+
productRows: getInvoicingCatalogPlanRows(products),
|
|
69
|
+
products,
|
|
70
|
+
productSort: listViewState.productSort,
|
|
71
|
+
count: listViewState.counts,
|
|
72
|
+
countsFetchState: listViewState.countsFetchState,
|
|
73
|
+
planFilters: listViewState.planFilters,
|
|
74
|
+
planNextCursor: listViewState.planNextCursor,
|
|
75
|
+
productFilters: listViewState.productFilters,
|
|
76
|
+
productNextCursor: listViewState.productNextCursor,
|
|
77
|
+
productFetchState: listViewState.productFetchState,
|
|
78
|
+
fetchState: listViewState.fetchState,
|
|
79
|
+
error: listViewState.error,
|
|
80
|
+
version: 1.0,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
@@ -1,20 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export const ALL_INVOICING_PRODUCT_SORT_KEYS = [
|
|
3
|
-
'product_name',
|
|
4
|
-
'product_code',
|
|
5
|
-
'type',
|
|
6
|
-
'pricing',
|
|
7
|
-
'usage',
|
|
8
|
-
'updated',
|
|
9
|
-
'status',
|
|
10
|
-
];
|
|
11
|
-
export const toInvoicingProductSortKey = (v) => stringToUnion(v, ALL_INVOICING_PRODUCT_SORT_KEYS);
|
|
12
|
-
export const INVOICING_PRODUCT_COLUMNS = [
|
|
13
|
-
{ key: 'product_name', sortable: true },
|
|
14
|
-
{ key: 'product_code', sortable: true },
|
|
15
|
-
{ key: 'type', sortable: true },
|
|
16
|
-
{ key: 'pricing', sortable: false },
|
|
17
|
-
{ key: 'usage', sortable: true },
|
|
18
|
-
{ key: 'updated', sortable: true },
|
|
19
|
-
{ key: 'status', sortable: true },
|
|
20
|
-
];
|
|
1
|
+
export {};
|