@zeniai/client-epic-state 5.2.41-beta6MM → 5.2.41-beta7MM
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/billPay/billTransaction/billTransactionReducer.d.ts +5 -1
- package/lib/entity/billPay/billTransaction/billTransactionReducer.js +17 -2
- package/lib/entity/invoicing/coupon/couponPayload.d.ts +8 -0
- package/lib/entity/invoicing/coupon/couponPayload.js +8 -0
- package/lib/entity/invoicing/coupon/couponState.d.ts +6 -0
- package/lib/entity/invoicing/dunningCase/dunningCaseTypes.d.ts +1 -1
- package/lib/entity/invoicing/plan/planSelector.d.ts +20 -0
- package/lib/entity/invoicing/plan/planSelector.js +42 -0
- package/lib/entity/invoicing/product/productPayload.d.ts +8 -1
- package/lib/entity/invoicing/product/productPayload.js +4 -1
- package/lib/entity/invoicing/product/productState.d.ts +16 -0
- package/lib/entity/jeSchedules/jeSchedulesReducer.d.ts +4 -1
- package/lib/entity/jeSchedules/jeSchedulesReducer.js +79 -5
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/entity/task/taskState.d.ts +1 -1
- package/lib/epic.d.ts +4 -1
- package/lib/epic.js +10 -4
- package/lib/esm/entity/billPay/billTransaction/billTransactionReducer.js +16 -1
- package/lib/esm/entity/invoicing/coupon/couponPayload.js +8 -0
- package/lib/esm/entity/invoicing/plan/planSelector.js +39 -0
- package/lib/esm/entity/invoicing/product/productPayload.js +4 -1
- package/lib/esm/entity/jeSchedules/jeSchedulesReducer.js +78 -4
- package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
- package/lib/esm/epic.js +10 -4
- package/lib/esm/index.js +8 -7
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +3 -2
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +39 -0
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +14 -1
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +10 -13
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +38 -17
- package/lib/esm/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +17 -1
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
- package/lib/esm/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +6 -0
- package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +74 -1
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
- package/lib/esm/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +6 -2
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +49 -14
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -11
- package/lib/esm/view/invoicing/createInvoice/createInvoiceSelector.js +28 -1
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +67 -35
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +23 -4
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.js +1 -7
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +19 -5
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +30 -7
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +16 -1
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +69 -6
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.js +22 -0
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.js +22 -4
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +18 -4
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +29 -6
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +28 -12
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +37 -2
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +43 -17
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +29 -6
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +30 -14
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +143 -8
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +44 -18
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +29 -8
- package/lib/esm/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
- package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +6 -6
- package/lib/esm/view/invoicing/invoicingFormDraft.js +78 -0
- package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +57 -9
- package/lib/esm/view/recommendation/recommendationPayload.js +3 -1
- package/lib/esm/view/recommendation/recommendationReducer.js +27 -7
- package/lib/esm/view/recommendation/recommendationSelector.js +1 -0
- package/lib/esm/view/recommendation/submitRecommendationFeedbackEpic.js +20 -8
- package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewReducer.js +87 -1
- package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +1 -0
- package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewState.js +4 -0
- package/lib/esm/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.js +97 -0
- package/lib/esm/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.js +85 -0
- package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewReducer.js +18 -1
- package/lib/esm/view/spendManagement/billPay/editBillView/editBillViewSelector.js +3 -0
- package/lib/esm/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.js +95 -0
- package/lib/index.d.ts +9 -8
- package/lib/index.js +54 -48
- package/lib/view/expenseAutomationView/epics/jeSchedule/actualMatching/ignoreActualMatchingSuggestionEpic.js +3 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.d.ts +20 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchFailedJePostingsEpic.js +43 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulePageEpic.js +13 -0
- package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +8 -11
- package/lib/view/expenseAutomationView/epics/jeSchedule/initializeJeScheduleLocalDataEpic.js +38 -17
- package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/jeSchedule/retryJeSchedulesEpic.js +17 -1
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +18 -0
- package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +18 -7
- package/lib/view/expenseAutomationView/reducers/actualMatchingViewReducer.js +6 -0
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +10 -3
- package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +76 -3
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
- package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +3 -0
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +8 -4
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.d.ts +1 -0
- package/lib/view/expenseAutomationView/selectors/actualMatchingViewSelector.js +7 -2
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +49 -14
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -10
- package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +16 -0
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +8 -5
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.d.ts +7 -2
- package/lib/view/invoicing/createInvoice/createInvoiceSelector.js +28 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +46 -5
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +69 -36
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +22 -11
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +17 -0
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +22 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewState.d.ts +2 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.d.ts +2 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.js +1 -7
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +17 -3
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +29 -6
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.d.ts +5 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +16 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +22 -11
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +46 -0
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +68 -5
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.d.ts +21 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.js +24 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.d.ts +9 -5
- package/lib/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.js +22 -4
- package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +18 -4
- package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +28 -5
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +5 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +29 -13
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +16 -7
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +37 -2
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +8 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.d.ts +15 -10
- package/lib/view/invoicing/editInvoicingCustomerDetailView/initializeInvoicingCustomerAddressEpic.js +42 -16
- package/lib/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingCustomerDetailView/seedInvoicingCustomerFormDraftEpic.js +28 -5
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.d.ts +5 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +31 -15
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +79 -12
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +145 -9
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +8 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.d.ts +15 -11
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/initializeInvoicingSubscriptionAddressEpic.js +42 -16
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +28 -7
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.d.ts +10 -0
- package/lib/view/invoicing/invoicingCatalogListView/invoicingCatalogListViewSelector.js +12 -0
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -2
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.js +6 -6
- package/lib/view/invoicing/invoicingFormDraft.d.ts +63 -0
- package/lib/view/invoicing/invoicingFormDraft.js +86 -0
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.d.ts +49 -0
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +59 -10
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +1 -1
- package/lib/view/recommendation/recommendationPayload.d.ts +1 -0
- package/lib/view/recommendation/recommendationPayload.js +5 -0
- package/lib/view/recommendation/recommendationReducer.d.ts +7 -1
- package/lib/view/recommendation/recommendationReducer.js +28 -8
- package/lib/view/recommendation/recommendationSelector.d.ts +2 -0
- package/lib/view/recommendation/recommendationSelector.js +3 -1
- package/lib/view/recommendation/recommendationState.d.ts +2 -1
- package/lib/view/recommendation/submitRecommendationFeedbackEpic.d.ts +2 -2
- package/lib/view/recommendation/submitRecommendationFeedbackEpic.js +18 -6
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewPayload.d.ts +19 -0
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewReducer.d.ts +10 -1
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewReducer.js +88 -2
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.d.ts +1 -0
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +1 -0
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewState.d.ts +7 -0
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewState.js +4 -0
- package/lib/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.d.ts +37 -0
- package/lib/view/spendManagement/billPay/billDetailView/epics/fetchBillRecommendationsEpic.js +104 -0
- package/lib/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.d.ts +24 -0
- package/lib/view/spendManagement/billPay/billDetailView/epics/fetchRecommendationsForBill.js +92 -0
- package/lib/view/spendManagement/billPay/editBillView/editBillViewReducer.d.ts +4 -1
- package/lib/view/spendManagement/billPay/editBillView/editBillViewReducer.js +19 -2
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.d.ts +1 -0
- package/lib/view/spendManagement/billPay/editBillView/editBillViewSelector.js +3 -0
- package/lib/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.d.ts +18 -0
- package/lib/view/spendManagement/billPay/editBillView/epics/applyBillRecommendationsToLocalStoreEpic.js +102 -0
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { clearAll } from '../../../rootActions';
|
|
3
|
+
import { applyInvoicingFormDraftEdit, applyInvoicingFormDraftFailure, applyInvoicingFormDraftSaved, applyInvoicingFormDraftSeed, } from '../invoicingFormDraft';
|
|
3
4
|
import { initialInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormHelper';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
fetchState: 'Not-Started',
|
|
@@ -21,7 +22,7 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
21
22
|
updateInvoicingCatalogItemFormDraft(draft, action) {
|
|
22
23
|
const { id, localData } = action.payload;
|
|
23
24
|
if (id != null) {
|
|
24
|
-
draft.editDraftById
|
|
25
|
+
applyInvoicingFormDraftEdit(draft.editDraftById, id, localData);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
28
|
draft.newItemDraft = localData;
|
|
@@ -42,6 +43,9 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
42
43
|
draft.error = undefined;
|
|
43
44
|
draft.savedItemId = action.payload.itemId;
|
|
44
45
|
draft.savedKind = action.payload.kind;
|
|
46
|
+
// An edit is refetched on success; keep the saved values on screen until
|
|
47
|
+
// that lands, and let it replace them.
|
|
48
|
+
applyInvoicingFormDraftSaved(draft.editDraftById, action.payload.itemId);
|
|
45
49
|
},
|
|
46
50
|
submitInvoicingCatalogItemFormFailure(draft, action) {
|
|
47
51
|
draft.fetchState = 'Error';
|
|
@@ -64,6 +68,7 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
64
68
|
fetchState: 'Error',
|
|
65
69
|
error: action.payload.error,
|
|
66
70
|
};
|
|
71
|
+
applyInvoicingFormDraftFailure(draft.editDraftById, action.payload.id, initialInvoicingCatalogItemFormLocalData);
|
|
67
72
|
},
|
|
68
73
|
fetchInvoicingCatalogItemDetailPage: {
|
|
69
74
|
reducer() {
|
|
@@ -79,14 +84,10 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
79
84
|
};
|
|
80
85
|
},
|
|
81
86
|
},
|
|
82
|
-
/**
|
|
83
|
-
* Seed the draft from the loaded record, once. Skipped when a draft already
|
|
84
|
-
* exists so a late-arriving refetch cannot overwrite in-progress edits.
|
|
85
|
-
*/
|
|
87
|
+
/** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
|
|
86
88
|
seedInvoicingCatalogItemFormDraft(draft, action) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
89
|
+
const { id, localData } = action.payload;
|
|
90
|
+
applyInvoicingFormDraftSeed(draft.editDraftById, id, localData);
|
|
90
91
|
},
|
|
91
92
|
runInvoicingCatalogPlanAction(draft, action) {
|
|
92
93
|
draft.actionStateById[action.payload.id] = {
|
|
@@ -125,13 +126,23 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
125
126
|
error: action.payload.error,
|
|
126
127
|
};
|
|
127
128
|
},
|
|
128
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Discard a form's draft — the catalog item's own when `id` is given,
|
|
131
|
+
* the create draft otherwise. Scoped to the one form on purpose: another
|
|
132
|
+
* catalog item's half-finished edit is not this form's to throw away.
|
|
133
|
+
* Clearing every draft at once is what `clearAll` is for.
|
|
134
|
+
*/
|
|
135
|
+
resetEditInvoicingCatalogItemDetailView(draft, action) {
|
|
129
136
|
draft.fetchState = 'Not-Started';
|
|
130
137
|
draft.error = undefined;
|
|
131
138
|
draft.savedItemId = undefined;
|
|
132
139
|
draft.savedKind = undefined;
|
|
133
|
-
|
|
134
|
-
|
|
140
|
+
const id = action.payload?.id;
|
|
141
|
+
if (id == null) {
|
|
142
|
+
draft.newItemDraft = { ...initialInvoicingCatalogItemFormLocalData };
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
delete draft.editDraftById[id];
|
|
135
146
|
},
|
|
136
147
|
},
|
|
137
148
|
extraReducers: (builder) => {
|
|
@@ -2,7 +2,8 @@ import { createSelector } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
3
|
import { getInvoicingPlanById, getInvoicingPlansByIds, } from '../../../entity/invoicing/plan/planSelector';
|
|
4
4
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
|
-
import {
|
|
5
|
+
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
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';
|
|
6
7
|
import { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, initialInvoicingCatalogItemFormLocalData, } from './invoicingCatalogItemFormHelper';
|
|
7
8
|
export const getEditInvoicingCatalogItemDetailViewState = (state) => ({
|
|
8
9
|
fetchState: state.editInvoicingCatalogItemDetailViewState.fetchState,
|
|
@@ -43,6 +44,21 @@ const NOT_STARTED = {
|
|
|
43
44
|
error: undefined,
|
|
44
45
|
fetchState: 'Not-Started',
|
|
45
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* The QuickBooks ids a price point's income account may be picked from.
|
|
49
|
+
*
|
|
50
|
+
* Memoized, and collapsing to one shared empty array while QBO is disconnected:
|
|
51
|
+
* the pages turn this into their picker options and re-seed their form defaults
|
|
52
|
+
* when those change, so a fresh array on every store change would reset the form
|
|
53
|
+
* under the user — including mid-save.
|
|
54
|
+
*/
|
|
55
|
+
const getInvoicingCatalogIncomeAccountIds = createSelector([
|
|
56
|
+
getInvoicingQboAccountOptions,
|
|
57
|
+
(state) => getInvoicingConfigView(state).qboAccountMappingKindOptions,
|
|
58
|
+
isInvoicingQboConnected,
|
|
59
|
+
], (accounts, qboAccountMappingKindOptions, isQboConnected) => isQboConnected
|
|
60
|
+
? invoicingQboAccountIdsForMappingSlot(accounts, qboAccountMappingKindOptions, INVOICING_INCOME_ACCOUNT_MAPPING_SLOT, INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES)
|
|
61
|
+
: NO_INVOICING_ACCOUNT_IDS);
|
|
46
62
|
export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
47
63
|
const { editDraftById, error, fetchState, newItemDraft, savedItemId, savedKind, } = state.editInvoicingCatalogItemDetailViewState;
|
|
48
64
|
const plan = id != null ? getInvoicingPlanById(state.invoicingPlanState, id) : undefined;
|
|
@@ -52,7 +68,7 @@ export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
52
68
|
// lands. Until then the page is showing its skeleton, so the blank shape here
|
|
53
69
|
// is never rendered.
|
|
54
70
|
const localData = id != null
|
|
55
|
-
? (editDraftById
|
|
71
|
+
? getInvoicingFormDraftLocalData(editDraftById, id, initialInvoicingCatalogItemFormLocalData)
|
|
56
72
|
: newItemDraft;
|
|
57
73
|
const allApplicableItemOptions = getInvoicingApplicableCatalogItemOptions(state);
|
|
58
74
|
const applicableItemOptions = id != null
|
|
@@ -90,9 +106,12 @@ export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
90
106
|
catalogProductLifecycleActionOptions,
|
|
91
107
|
recordState,
|
|
92
108
|
fieldHelp: invoicingFieldHelpForGroup(state, 'catalog'),
|
|
109
|
+
isFormLoading: isInvoicingAccountingPickerDataLoading(state) ||
|
|
110
|
+
isInvoicingFormDraftPending(editDraftById, id),
|
|
93
111
|
isQboPickerDataLoading: isInvoicingAccountingPickerDataLoading(state),
|
|
94
|
-
qboAccountHierarchy: qboView?.nestedAccountHierarchy ??
|
|
95
|
-
qboClassHierarchy: qboView?.nestedClassHierarchy ??
|
|
112
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? NO_INVOICING_ACCOUNT_HIERARCHY,
|
|
113
|
+
qboClassHierarchy: qboView?.nestedClassHierarchy ?? NO_INVOICING_CLASS_HIERARCHY,
|
|
114
|
+
qboIncomeAccountIds: getInvoicingCatalogIncomeAccountIds(state),
|
|
96
115
|
applicabilityValues: INVOICING_CATALOG_APPLICABILITY_VALUES,
|
|
97
116
|
applicableItemOptions,
|
|
98
117
|
localData,
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormHelper.js
CHANGED
|
@@ -3,13 +3,7 @@
|
|
|
3
3
|
* for pricing model, tier type, proration or applicability yet, so these stay
|
|
4
4
|
* here until it does. Everything else on this form comes from `/1.0/config`.
|
|
5
5
|
*/
|
|
6
|
-
export const INVOICING_CATALOG_PRICING_MODEL_VALUES = [
|
|
7
|
-
'flat_fee',
|
|
8
|
-
'per_unit',
|
|
9
|
-
'tiered',
|
|
10
|
-
'volume',
|
|
11
|
-
'stairstep',
|
|
12
|
-
];
|
|
6
|
+
export const INVOICING_CATALOG_PRICING_MODEL_VALUES = ['flat_fee', 'per_unit', 'tiered', 'volume', 'stairstep'];
|
|
13
7
|
export const INVOICING_CATALOG_TIER_TYPE_VALUES = [
|
|
14
8
|
'per_unit',
|
|
15
9
|
'flat_fee',
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { from } from 'rxjs';
|
|
1
|
+
import { forkJoin, from } from 'rxjs';
|
|
2
2
|
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
3
|
import { mergeInvoicingPlanSubFamily, updateInvoicingPlans, } from '../../../entity/invoicing/plan/planReducer';
|
|
4
4
|
import { updateInvoicingProducts } from '../../../entity/invoicing/product/productReducer';
|
|
@@ -7,7 +7,7 @@ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
|
7
7
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
8
8
|
import { addInvoicingCatalogItem } from '../invoicingCatalogListView/invoicingCatalogListViewReducer';
|
|
9
9
|
import { getInvoicingCatalogAccountingLookup } from '../invoicingQboView/invoicingQboViewSelector';
|
|
10
|
-
import { localDataToSaveInvoicingCatalogItemPayload, } from './editInvoicingCatalogItemDetailViewPayload';
|
|
10
|
+
import { localDataToCreateInvoicingCatalogProductPayloads, localDataToSaveInvoicingCatalogItemPayload, } from './editInvoicingCatalogItemDetailViewPayload';
|
|
11
11
|
import { submitInvoicingCatalogItemForm, submitInvoicingCatalogItemFormFailure, submitInvoicingCatalogItemFormSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
12
12
|
export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => submitInvoicingCatalogItemForm.match(action)), mergeMap((action) => {
|
|
13
13
|
const { id } = action.payload;
|
|
@@ -17,8 +17,9 @@ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actio
|
|
|
17
17
|
// class become the records the service stores. Price points ride along
|
|
18
18
|
// nested, so the detail page and the create/edit form share one request.
|
|
19
19
|
const viewState = state.editInvoicingCatalogItemDetailViewState;
|
|
20
|
-
const localData = (id != null
|
|
21
|
-
viewState.
|
|
20
|
+
const localData = (id != null
|
|
21
|
+
? viewState.editDraftById[id]?.localData
|
|
22
|
+
: viewState.newItemDraft) ?? viewState.newItemDraft;
|
|
22
23
|
const data = localDataToSaveInvoicingCatalogItemPayload(localData, id == null, accountingLookup);
|
|
23
24
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
24
25
|
const path = id != null
|
|
@@ -80,7 +81,20 @@ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actio
|
|
|
80
81
|
}));
|
|
81
82
|
return resultActions;
|
|
82
83
|
};
|
|
83
|
-
|
|
84
|
+
// Price points added on an edit form cannot ride in the update:
|
|
85
|
+
// it addresses them by id and they have none yet. They are created
|
|
86
|
+
// against the item that was just saved, and their responses join
|
|
87
|
+
// the same success — one of them failing is the whole save
|
|
88
|
+
// failing, since the item on screen would otherwise claim price
|
|
89
|
+
// points the service never stored. A create needs none of this:
|
|
90
|
+
// its price points are nested in the item body.
|
|
91
|
+
const newProductPayloads = id != null
|
|
92
|
+
? localDataToCreateInvoicingCatalogProductPayloads(localData, savedItem.id, accountingLookup)
|
|
93
|
+
: [];
|
|
94
|
+
if (newProductPayloads.length === 0) {
|
|
95
|
+
return completeSave([]);
|
|
96
|
+
}
|
|
97
|
+
return forkJoin(newProductPayloads.map((productPayload) => zeniAPI.postAndGetJSON(`${baseUrl}/catalog/products`, productPayload))).pipe(mergeMap((productResponses) => completeSave(productResponses)));
|
|
84
98
|
}
|
|
85
99
|
return from([
|
|
86
100
|
submitInvoicingCatalogItemFormFailure(response.status),
|
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
import { EMPTY, of } from 'rxjs';
|
|
2
2
|
import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
|
|
3
3
|
import { getInvoicingPlanById } from '../../../entity/invoicing/plan/planSelector';
|
|
4
|
-
import { seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
4
|
+
import { fetchInvoicingCatalogItemDetailPage, seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
5
5
|
import { entityToInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormHelper';
|
|
6
6
|
/**
|
|
7
|
-
* Seeds the edit draft from the record the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Seeds the edit draft from the record, so the form has its values before it
|
|
8
|
+
* mounts. The reducer ignores a seed once the draft holds the record, which is
|
|
9
|
+
* what stops a background refetch from overwriting edits in progress.
|
|
10
|
+
*
|
|
11
|
+
* Opening the page counts as a trigger, not just the detail response: the page
|
|
12
|
+
* fetch is cache-guarded, so re-opening a form for a record already loaded this
|
|
13
|
+
* session issues no request at all — and a draft cleared in between (by a save
|
|
14
|
+
* or a cancel) would have nothing left to seed it.
|
|
11
15
|
*/
|
|
12
|
-
export const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe(filter(updateInvoicingCatalogItemDetail.match
|
|
13
|
-
|
|
16
|
+
export const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe(filter((action) => updateInvoicingCatalogItemDetail.match(action) ||
|
|
17
|
+
fetchInvoicingCatalogItemDetailPage.match(action)), withLatestFrom(state$), mergeMap(([action, state]) => {
|
|
18
|
+
const id = action.payload.id;
|
|
19
|
+
if (id == null) {
|
|
20
|
+
return EMPTY;
|
|
21
|
+
}
|
|
22
|
+
// The entity alone does not say the whole record is loaded — the list
|
|
23
|
+
// endpoints merge their own list-shaped rows into the same store. Only a
|
|
24
|
+
// completed detail load does, which is also exactly when the page's
|
|
25
|
+
// cache-guarded fetch issues no request and this is the sole seed.
|
|
26
|
+
// A forced refetch is the caller asking for fresh data: the response will
|
|
27
|
+
// seed, and seeding first from the entity as it stands would mark the
|
|
28
|
+
// draft loaded and lock that response out.
|
|
29
|
+
if (fetchInvoicingCatalogItemDetailPage.match(action) &&
|
|
30
|
+
(action.payload.cacheOverride === true ||
|
|
31
|
+
state.editInvoicingCatalogItemDetailViewState.recordStateById[id]
|
|
32
|
+
?.fetchState !== 'Completed')) {
|
|
33
|
+
return EMPTY;
|
|
34
|
+
}
|
|
35
|
+
// Nothing to seed from on a cold open; the detail response triggers this
|
|
36
|
+
// again once it lands.
|
|
14
37
|
const plan = getInvoicingPlanById(state.invoicingPlanState, id);
|
|
15
38
|
if (plan == null) {
|
|
16
39
|
return EMPTY;
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { toAccountPayload } from '../../../entity/account/accountPayload';
|
|
1
2
|
/**
|
|
2
3
|
* Build the create/update discount request body from the form draft (snake_case
|
|
3
4
|
* matching the `/discounts` schema). On create the coupon id is part of the
|
|
4
5
|
* body; on edit it is the URL param, so it is omitted here.
|
|
6
|
+
*
|
|
7
|
+
* `accountByQboId` resolves the discounts-account picker back to the account
|
|
8
|
+
* record the body carries, the same way the catalog and QBO settings bodies do.
|
|
5
9
|
*/
|
|
6
|
-
export const localDataToSaveInvoicingCouponPayload = (localData, isCreate) => {
|
|
10
|
+
export const localDataToSaveInvoicingCouponPayload = (localData, isCreate, accountByQboId) => {
|
|
7
11
|
const data = {
|
|
8
12
|
apply_on: localData.applyOn,
|
|
9
13
|
discount_type: localData.discountType,
|
|
@@ -54,5 +58,16 @@ export const localDataToSaveInvoicingCouponPayload = (localData, isCreate) => {
|
|
|
54
58
|
if (invoiceNotes !== '') {
|
|
55
59
|
data.invoice_notes = invoiceNotes;
|
|
56
60
|
}
|
|
61
|
+
// Omitted rather than sent as `null` when there is none: the service reads a
|
|
62
|
+
// blank discounts account as "not given" and leaves what it has, which is
|
|
63
|
+
// what keeps a form that never showed the picker — QBO disconnected — from
|
|
64
|
+
// clearing an account set elsewhere.
|
|
65
|
+
const discountsAccountId = localData.discountsAccountId.trim();
|
|
66
|
+
const discountsAccount = discountsAccountId !== ''
|
|
67
|
+
? accountByQboId?.(discountsAccountId)
|
|
68
|
+
: undefined;
|
|
69
|
+
if (discountsAccount != null) {
|
|
70
|
+
data.discounts_account = toAccountPayload(discountsAccount);
|
|
71
|
+
}
|
|
57
72
|
return data;
|
|
58
73
|
};
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { clearAll } from '../../../rootActions';
|
|
3
|
+
import { applyInvoicingFormDraftEdit, applyInvoicingFormDraftFailure, applyInvoicingFormDraftSaved, applyInvoicingFormDraftSeed, } from '../invoicingFormDraft';
|
|
3
4
|
import { initialInvoicingCouponFormLocalData, } from './editInvoicingCouponDetailViewState';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
fetchState: 'Not-Started',
|
|
@@ -20,7 +21,7 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
20
21
|
updateInvoicingCouponFormDraft(draft, action) {
|
|
21
22
|
const { id, localData } = action.payload;
|
|
22
23
|
if (id != null) {
|
|
23
|
-
draft.editDraftById
|
|
24
|
+
applyInvoicingFormDraftEdit(draft.editDraftById, id, localData);
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
27
|
draft.newCouponDraft = localData;
|
|
@@ -50,6 +51,9 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
50
51
|
draft.fetchState = 'Completed';
|
|
51
52
|
draft.error = undefined;
|
|
52
53
|
draft.savedCouponId = action.payload.couponId;
|
|
54
|
+
// An edit is refetched on success; keep the saved values on screen until
|
|
55
|
+
// that lands, and let it replace them.
|
|
56
|
+
applyInvoicingFormDraftSaved(draft.editDraftById, action.payload.couponId);
|
|
53
57
|
},
|
|
54
58
|
submitInvoicingCouponFormFailure(draft, action) {
|
|
55
59
|
draft.fetchState = 'Error';
|
|
@@ -85,15 +89,12 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
85
89
|
fetchState: 'Error',
|
|
86
90
|
error: action.payload.status,
|
|
87
91
|
};
|
|
92
|
+
applyInvoicingFormDraftFailure(draft.editDraftById, action.payload.id, initialInvoicingCouponFormLocalData);
|
|
88
93
|
},
|
|
89
|
-
/**
|
|
90
|
-
* Seed the draft from the loaded record, once. Skipped when a draft already
|
|
91
|
-
* exists so a late refetch cannot overwrite in-progress edits.
|
|
92
|
-
*/
|
|
94
|
+
/** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
|
|
93
95
|
seedInvoicingCouponFormDraft(draft, action) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
96
|
+
const { id, localData } = action.payload;
|
|
97
|
+
applyInvoicingFormDraftSeed(draft.editDraftById, id, localData);
|
|
97
98
|
},
|
|
98
99
|
runInvoicingDiscountAction(draft, action) {
|
|
99
100
|
draft.actionStateById[action.payload.id] = {
|
|
@@ -113,12 +114,22 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
113
114
|
error: action.payload.error,
|
|
114
115
|
};
|
|
115
116
|
},
|
|
116
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Discard a form's draft — the coupon's own when `id` is given,
|
|
119
|
+
* the create draft otherwise. Scoped to the one form on purpose: another
|
|
120
|
+
* coupon's half-finished edit is not this form's to throw away.
|
|
121
|
+
* Clearing every draft at once is what `clearAll` is for.
|
|
122
|
+
*/
|
|
123
|
+
resetEditInvoicingCouponDetailView(draft, action) {
|
|
117
124
|
draft.fetchState = 'Not-Started';
|
|
118
125
|
draft.error = undefined;
|
|
119
126
|
draft.savedCouponId = undefined;
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
const id = action.payload?.id;
|
|
128
|
+
if (id == null) {
|
|
129
|
+
draft.newCouponDraft = { ...initialInvoicingCouponFormLocalData };
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
delete draft.editDraftById[id];
|
|
122
133
|
},
|
|
123
134
|
},
|
|
124
135
|
extraReducers: (builder) => {
|
|
@@ -1,13 +1,32 @@
|
|
|
1
|
+
import { createSelector } from '@reduxjs/toolkit';
|
|
1
2
|
import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
2
3
|
import { getInvoicingCouponById } from '../../../entity/invoicing/coupon/couponSelector';
|
|
3
4
|
import { toInvoicingFormOption, } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
4
5
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
|
-
import {
|
|
6
|
+
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
7
|
+
import { INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES, INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT, NO_INVOICING_ACCOUNT_HIERARCHY, NO_INVOICING_ACCOUNT_IDS, getInvoicingQboAccountOptions, getInvoicingQboView, invoicingQboAccountByQboId, invoicingQboAccountIdsForMappingSlot, isInvoicingAccountingPickerDataLoading, isInvoicingQboConnected, } from '../invoicingQboView/invoicingQboViewSelector';
|
|
8
|
+
import { getInvoicingSettings, getInvoicingSettingsFetchState, } from '../settingsView/settingsViewSelector';
|
|
9
|
+
import { initialInvoicingCouponFormLocalData, invoicingCouponDiscountsAccountIdForCreate, } from './editInvoicingCouponDetailViewState';
|
|
6
10
|
/**
|
|
7
11
|
* Bundled view for the discount create/edit form: the save fetch state/error,
|
|
8
12
|
* the id of the coupon last saved, and — when a `couponId` is passed (edit
|
|
9
13
|
* mode) — the existing coupon entity to prefill the form.
|
|
10
14
|
*/
|
|
15
|
+
/**
|
|
16
|
+
* The QuickBooks ids the discounts account may be picked from.
|
|
17
|
+
*
|
|
18
|
+
* Memoized, and collapsing to one shared empty array while QBO is disconnected:
|
|
19
|
+
* the form turns this into its picker options and re-seeds its defaults when
|
|
20
|
+
* those change, so a fresh array on every store change would reset the form
|
|
21
|
+
* under the user until their first edit.
|
|
22
|
+
*/
|
|
23
|
+
const getInvoicingCouponDiscountsAccountIds = createSelector([
|
|
24
|
+
getInvoicingQboAccountOptions,
|
|
25
|
+
(state) => getInvoicingConfigView(state).qboAccountMappingKindOptions,
|
|
26
|
+
isInvoicingQboConnected,
|
|
27
|
+
], (accounts, qboAccountMappingKindOptions, isQboConnected) => isQboConnected
|
|
28
|
+
? invoicingQboAccountIdsForMappingSlot(accounts, qboAccountMappingKindOptions, INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT, INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES)
|
|
29
|
+
: NO_INVOICING_ACCOUNT_IDS);
|
|
11
30
|
const NOT_STARTED = {
|
|
12
31
|
error: undefined,
|
|
13
32
|
fetchState: 'Not-Started',
|
|
@@ -23,6 +42,9 @@ export const getEditInvoicingCouponDetailViewState = (state, couponId) => {
|
|
|
23
42
|
fetchState: 'Not-Started',
|
|
24
43
|
})
|
|
25
44
|
: { error: undefined, fetchState: 'Completed' };
|
|
45
|
+
const coupon = couponId != null
|
|
46
|
+
? getInvoicingCouponById(state.invoicingCouponState, couponId)
|
|
47
|
+
: undefined;
|
|
26
48
|
return {
|
|
27
49
|
actionState: couponId != null
|
|
28
50
|
? (state.editInvoicingCouponDetailViewState.actionStateById[couponId] ??
|
|
@@ -36,9 +58,9 @@ export const getEditInvoicingCouponDetailViewState = (state, couponId) => {
|
|
|
36
58
|
{ error: undefined, fetchState: configFetchState },
|
|
37
59
|
]),
|
|
38
60
|
recordState,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
61
|
+
isFormLoading: isInvoicingFormDraftPending(state.editInvoicingCouponDetailViewState.editDraftById, couponId),
|
|
62
|
+
coupon,
|
|
63
|
+
discountsAccountName: invoicingQboAccountByQboId(state, coupon?.discountsAccountId)?.accountName,
|
|
42
64
|
savedCouponId,
|
|
43
65
|
fetchState,
|
|
44
66
|
error,
|
|
@@ -58,16 +80,57 @@ export const getInvoicingCouponFormView = (state, couponId) => {
|
|
|
58
80
|
// `seedInvoicingCouponFormDraftEpic` when the detail load lands. Until then
|
|
59
81
|
// the page is showing its skeleton.
|
|
60
82
|
const localData = couponId != null
|
|
61
|
-
? (editDraftById
|
|
83
|
+
? getInvoicingFormDraftLocalData(editDraftById, couponId, initialInvoicingCouponFormLocalData)
|
|
62
84
|
: newCouponDraft;
|
|
63
85
|
const { billingPeriodUnitOptions, discountApplyOnOptions, discountDurationTypeOptions, discountTypeOptions, } = getInvoicingConfigView(state);
|
|
86
|
+
const isQboConnected = isInvoicingQboConnected(state);
|
|
87
|
+
const qboView = isQboConnected ? getInvoicingQboView(state) : undefined;
|
|
88
|
+
const isQboPickerDataLoading = isInvoicingAccountingPickerDataLoading(state);
|
|
89
|
+
const settingsFetchState = getInvoicingSettingsFetchState(state).fetchState;
|
|
90
|
+
// Only a create reads the settings, and only until they arrive: an `Error`
|
|
91
|
+
// is a create that starts on no account, not a page that never renders.
|
|
92
|
+
const isCreateSeedPending = couponId == null &&
|
|
93
|
+
(settingsFetchState === 'Not-Started' ||
|
|
94
|
+
settingsFetchState === 'In-Progress');
|
|
64
95
|
return {
|
|
65
96
|
...base,
|
|
66
97
|
applyOnOptions: discountApplyOnOptions.map(toInvoicingFormOption),
|
|
67
98
|
discountTypeOptions: discountTypeOptions.map(toInvoicingFormOption),
|
|
68
99
|
durationTypeOptions: discountDurationTypeOptions.map(toInvoicingFormOption),
|
|
69
|
-
|
|
100
|
+
isQboConnected,
|
|
101
|
+
isQboPickerDataLoading,
|
|
102
|
+
// Widened past the record and config the detail page waits on: the form
|
|
103
|
+
// also renders from the account list, and seeds a create from the settings
|
|
104
|
+
// discounts account. A form that mounted before those landed would offer an
|
|
105
|
+
// empty picker and save a coupon with no account of its own — not wrong,
|
|
106
|
+
// since blank means "use the settings account", but not what the user was
|
|
107
|
+
// shown either. Widened here rather than on the base view, so the detail
|
|
108
|
+
// page does not start waiting on lists it never renders.
|
|
109
|
+
//
|
|
110
|
+
// Only while they are still coming, though, and the settings only on a
|
|
111
|
+
// create: a coupon saves fine without a discounts account, so neither is
|
|
112
|
+
// allowed to hold the form behind a skeleton once it has failed.
|
|
113
|
+
pageFetchState: reduceAllFetchState([
|
|
114
|
+
base.pageFetchState,
|
|
115
|
+
{
|
|
116
|
+
error: undefined,
|
|
117
|
+
fetchState: isQboPickerDataLoading || isCreateSeedPending
|
|
118
|
+
? 'In-Progress'
|
|
119
|
+
: 'Completed',
|
|
120
|
+
},
|
|
121
|
+
]),
|
|
122
|
+
localData: couponId != null
|
|
123
|
+
? localData
|
|
124
|
+
: {
|
|
125
|
+
...localData,
|
|
126
|
+
// Seeded from settings only while the draft has none of its own, so
|
|
127
|
+
// the picker shows the account a create would post against before
|
|
128
|
+
// the user touches it, and stops seeding the moment they pick.
|
|
129
|
+
discountsAccountId: invoicingCouponDiscountsAccountIdForCreate(localData.discountsAccountId, getInvoicingSettings(state)?.qbo?.account_mappings),
|
|
130
|
+
},
|
|
70
131
|
mode: couponId != null ? 'edit' : 'create',
|
|
71
132
|
periodUnitOptions: billingPeriodUnitOptions.map(toInvoicingFormOption),
|
|
133
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? NO_INVOICING_ACCOUNT_HIERARCHY,
|
|
134
|
+
qboIncomeAccountIds: getInvoicingCouponDiscountsAccountIds(state),
|
|
72
135
|
};
|
|
73
136
|
};
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { getInvoicingQboAccountMappingId, } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
1
2
|
export const initialInvoicingCouponFormLocalData = {
|
|
2
3
|
applyOn: 'invoice_amount',
|
|
3
4
|
couponCode: '',
|
|
4
5
|
couponId: '',
|
|
5
6
|
discountPercentage: '',
|
|
6
7
|
discountQuantity: '',
|
|
8
|
+
discountsAccountId: '',
|
|
7
9
|
discountType: 'percentage',
|
|
8
10
|
durationType: 'one_time',
|
|
9
11
|
invoiceName: '',
|
|
@@ -29,6 +31,10 @@ export const entityToInvoicingCouponFormLocalData = (coupon) => {
|
|
|
29
31
|
? String(coupon.discountPercentage)
|
|
30
32
|
: '',
|
|
31
33
|
discountQuantity: coupon.discountQuantity != null ? String(coupon.discountQuantity) : '',
|
|
34
|
+
// The coupon's own account, never the current setting: an edit shows what
|
|
35
|
+
// this coupon will post against, which is what was stored when it was
|
|
36
|
+
// saved even if the settings default has moved since.
|
|
37
|
+
discountsAccountId: coupon.discountsAccountId ?? '',
|
|
32
38
|
discountType: coupon.discountType ?? 'percentage',
|
|
33
39
|
durationType: coupon.durationType ?? 'one_time',
|
|
34
40
|
invoiceName: coupon.invoiceName ?? '',
|
|
@@ -41,3 +47,19 @@ export const entityToInvoicingCouponFormLocalData = (coupon) => {
|
|
|
41
47
|
validTill: coupon.validTill != null ? coupon.validTill.format('YYYY-MM-DD') : '',
|
|
42
48
|
};
|
|
43
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* The discounts account a create starts from: the draft's own pick, or the QBO
|
|
52
|
+
* settings discounts account while the user has not made one. Read by both the
|
|
53
|
+
* form view and the save, so what the picker shows is what the request sends —
|
|
54
|
+
* a create that leaves the picker alone still stores the settings account on
|
|
55
|
+
* the coupon rather than relying on the setting staying put.
|
|
56
|
+
*
|
|
57
|
+
* Create only. An edit shows the coupon's stored account, so a coupon saved
|
|
58
|
+
* without one keeps showing none.
|
|
59
|
+
*/
|
|
60
|
+
export const invoicingCouponDiscountsAccountIdForCreate = (discountsAccountId, accountMappings) => {
|
|
61
|
+
const pickedAccountId = discountsAccountId.trim();
|
|
62
|
+
return pickedAccountId !== ''
|
|
63
|
+
? pickedAccountId
|
|
64
|
+
: (getInvoicingQboAccountMappingId(accountMappings ?? undefined, 'discounts_account') ?? '');
|
|
65
|
+
};
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/fetchInvoicingCouponDetailPageEpic.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { EMPTY, from } from 'rxjs';
|
|
2
2
|
import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
|
|
3
3
|
import { fetchInvoicingConfig } from '../invoicingConfigView/invoicingConfigViewReducer';
|
|
4
|
+
import { fetchInvoicingAccountingPickers, fetchInvoicingQboConnection, } from '../invoicingQboView/invoicingQboViewReducer';
|
|
5
|
+
import { fetchInvoicingSettings } from '../settingsView/settingsViewReducer';
|
|
4
6
|
import { fetchInvoicingCouponDetail, fetchInvoicingCouponDetailPage, } from './editInvoicingCouponDetailViewReducer';
|
|
5
7
|
/**
|
|
6
8
|
* Fetch unless the endpoint is already loaded or in flight — or always when the
|
|
@@ -10,10 +12,12 @@ const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
|
|
|
10
12
|
(fetchStateAndError.fetchState !== 'Completed' &&
|
|
11
13
|
fetchStateAndError.fetchState !== 'In-Progress');
|
|
12
14
|
/**
|
|
13
|
-
* Orchestrates the discount
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Orchestrates the discount pages: one action fans out to the coupon record,
|
|
16
|
+
* the invoicing config behind its dropdowns and field help, and the QuickBooks
|
|
17
|
+
* connection, account list and settings the form's Discounts account picker
|
|
18
|
+
* renders and seeds from — each skipped when already cached. The page reads a
|
|
19
|
+
* single reduced fetch state off the view, so the form mounts once with real
|
|
20
|
+
* values.
|
|
17
21
|
*/
|
|
18
22
|
export const fetchInvoicingCouponDetailPageEpic = (actions$, state$) => actions$.pipe(filter(fetchInvoicingCouponDetailPage.match), withLatestFrom(state$), mergeMap(([action, state]) => {
|
|
19
23
|
const { cacheOverride = false, id } = action.payload;
|
|
@@ -32,5 +36,19 @@ export const fetchInvoicingCouponDetailPageEpic = (actions$, state$) => actions$
|
|
|
32
36
|
if (shouldFetch({ error: configState.error, fetchState: configState.fetchState }, cacheOverride)) {
|
|
33
37
|
pageActions.push(fetchInvoicingConfig());
|
|
34
38
|
}
|
|
39
|
+
const qboState = state.invoicingQboViewState;
|
|
40
|
+
if (shouldFetch(qboState.connectionFetchState, cacheOverride)) {
|
|
41
|
+
pageActions.push(fetchInvoicingQboConnection());
|
|
42
|
+
}
|
|
43
|
+
// The picker epic tops up the shared account list and skips what the
|
|
44
|
+
// store already holds, so this is safe to ask for on every open.
|
|
45
|
+
pageActions.push(fetchInvoicingAccountingPickers());
|
|
46
|
+
const settingsState = state.invoicingSettingsViewState;
|
|
47
|
+
if (shouldFetch({ error: settingsState.error, fetchState: settingsState.fetchState }, cacheOverride)) {
|
|
48
|
+
// A create seeds its Discounts account from the settings mapping, so
|
|
49
|
+
// the settings are page data here rather than a settings-screen
|
|
50
|
+
// concern.
|
|
51
|
+
pageActions.push(fetchInvoicingSettings());
|
|
52
|
+
}
|
|
35
53
|
return pageActions.length > 0 ? from(pageActions) : EMPTY;
|
|
36
54
|
}));
|
|
@@ -5,8 +5,11 @@ import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiE
|
|
|
5
5
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
6
6
|
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
7
7
|
import { addInvoicingCouponToList } from '../couponView/couponViewReducer';
|
|
8
|
+
import { invoicingQboAccountByQboId } from '../invoicingQboView/invoicingQboViewSelector';
|
|
9
|
+
import { getInvoicingSettings } from '../settingsView/settingsViewSelector';
|
|
8
10
|
import { localDataToSaveInvoicingCouponPayload, } from './editInvoicingCouponDetailViewPayload';
|
|
9
11
|
import { saveInvoicingCoupon, submitInvoicingCouponForm, submitInvoicingCouponFormFailure, submitInvoicingCouponFormSuccess, } from './editInvoicingCouponDetailViewReducer';
|
|
12
|
+
import { invoicingCouponDiscountsAccountIdForCreate } from './editInvoicingCouponDetailViewState';
|
|
10
13
|
export const saveInvoicingCouponEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => submitInvoicingCouponForm.match(action) ||
|
|
11
14
|
saveInvoicingCoupon.match(action)), mergeMap((action) => {
|
|
12
15
|
const { id } = action.payload;
|
|
@@ -14,11 +17,22 @@ export const saveInvoicingCouponEpic = (actions$, state$, zeniAPI) => actions$.p
|
|
|
14
17
|
const data = saveInvoicingCoupon.match(action)
|
|
15
18
|
? action.payload.data
|
|
16
19
|
: (() => {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
+
const state = state$.value;
|
|
21
|
+
const viewState = state.editInvoicingCouponDetailViewState;
|
|
22
|
+
const draft = (id != null
|
|
23
|
+
? viewState.editDraftById[id]?.localData
|
|
20
24
|
: viewState.newCouponDraft) ?? viewState.newCouponDraft;
|
|
21
|
-
|
|
25
|
+
// The create default is resolved here as well as in the form view,
|
|
26
|
+
// so a create that never touched the picker still persists the
|
|
27
|
+
// settings account on the coupon instead of leaving it to whatever
|
|
28
|
+
// the setting says the day an invoice is raised.
|
|
29
|
+
const localData = id == null
|
|
30
|
+
? {
|
|
31
|
+
...draft,
|
|
32
|
+
discountsAccountId: invoicingCouponDiscountsAccountIdForCreate(draft.discountsAccountId, getInvoicingSettings(state)?.qbo?.account_mappings),
|
|
33
|
+
}
|
|
34
|
+
: draft;
|
|
35
|
+
return localDataToSaveInvoicingCouponPayload(localData, id == null, (qboId) => invoicingQboAccountByQboId(state, qboId));
|
|
22
36
|
})();
|
|
23
37
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
24
38
|
const path = id != null
|