@zeniai/client-epic-state 5.1.43-betaAK1 → 5.1.43-betaAK3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/lib/esm/index.js +7 -4
  2. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +137 -1
  3. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +31 -6
  4. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +24 -7
  5. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig.js +152 -0
  6. package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +22 -6
  7. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +59 -1
  8. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +39 -10
  9. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +21 -9
  10. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/invoicingCouponFormConfig.js +44 -0
  11. package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +20 -12
  12. package/lib/esm/view/invoicing/recordPayment/recordPaymentEpic.js +5 -3
  13. package/lib/esm/view/invoicing/recordPayment/recordPaymentFormConfig.js +37 -0
  14. package/lib/esm/view/invoicing/recordPayment/recordPaymentPayload.js +32 -1
  15. package/lib/esm/view/invoicing/recordPayment/recordPaymentReducer.js +11 -5
  16. package/lib/esm/view/invoicing/recordPayment/recordPaymentSelector.js +12 -0
  17. package/lib/index.d.ts +13 -6
  18. package/lib/index.js +26 -7
  19. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.d.ts +7 -0
  20. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewPayload.js +139 -0
  21. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +17 -4
  22. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +32 -7
  23. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +11 -0
  24. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +24 -7
  25. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewState.d.ts +51 -1
  26. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig.d.ts +32 -0
  27. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig.js +159 -0
  28. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.d.ts +3 -3
  29. package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +21 -5
  30. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.d.ts +7 -0
  31. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewPayload.js +61 -0
  32. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.d.ts +17 -4
  33. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +40 -11
  34. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +6 -2
  35. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +21 -9
  36. package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.d.ts +25 -1
  37. package/lib/view/invoicing/editInvoicingCouponDetailView/invoicingCouponFormConfig.d.ts +5 -0
  38. package/lib/view/invoicing/editInvoicingCouponDetailView/invoicingCouponFormConfig.js +48 -0
  39. package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.d.ts +3 -3
  40. package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +19 -11
  41. package/lib/view/invoicing/recordPayment/recordPaymentEpic.d.ts +3 -3
  42. package/lib/view/invoicing/recordPayment/recordPaymentEpic.js +4 -2
  43. package/lib/view/invoicing/recordPayment/recordPaymentFormConfig.d.ts +8 -0
  44. package/lib/view/invoicing/recordPayment/recordPaymentFormConfig.js +40 -0
  45. package/lib/view/invoicing/recordPayment/recordPaymentPayload.d.ts +7 -0
  46. package/lib/view/invoicing/recordPayment/recordPaymentPayload.js +34 -0
  47. package/lib/view/invoicing/recordPayment/recordPaymentReducer.d.ts +4 -3
  48. package/lib/view/invoicing/recordPayment/recordPaymentReducer.js +12 -6
  49. package/lib/view/invoicing/recordPayment/recordPaymentSelector.d.ts +12 -0
  50. package/lib/view/invoicing/recordPayment/recordPaymentSelector.js +14 -1
  51. package/lib/view/invoicing/recordPayment/recordPaymentState.d.ts +18 -2
  52. package/package.json +1 -1
package/lib/esm/index.js CHANGED
@@ -717,22 +717,25 @@ export { getInvoiceListView } from './view/invoicing/invoiceList/invoiceListSele
717
717
  export { clearAllInvoiceDetail, fetchInvoiceDetail, } from './view/invoicing/invoiceDetail/invoiceDetailReducer';
718
718
  export { getInvoiceDetail } from './view/invoicing/invoiceDetail/invoiceDetailSelector';
719
719
  export { createInvoice, resetCreateInvoice, } from './view/invoicing/createInvoice/createInvoiceReducer';
720
- export { recordPayment, resetRecordPayment, } from './view/invoicing/recordPayment/recordPaymentReducer';
720
+ export { resetRecordPayment, submitRecordPayment, updateRecordPaymentFormDraft, } from './view/invoicing/recordPayment/recordPaymentReducer';
721
+ export { INVOICING_PAYMENT_GATEWAY_VALUES, INVOICING_PAYMENT_METHOD_VALUES, initialRecordPaymentFormLocalData, } from './view/invoicing/recordPayment/recordPaymentFormConfig';
721
722
  export { clearInvoicingOverview, fetchInvoicingOverview, } from './view/invoicing/invoicingOverview/invoicingOverviewReducer';
722
723
  export { buildPeriodOptions, getInvoicingOverview, } from './view/invoicing/invoicingOverview/invoicingOverviewSelector';
723
724
  export { clearInvoicingAuditView, fetchInvoicingAuditLog, } from './view/invoicing/auditView/auditViewReducer';
724
725
  export { getInvoicingAuditLogFetchState, getInvoicingAuditLogFilters, getInvoicingAuditLogHasMore, getInvoicingAuditLogItems, getInvoicingAuditLogNextCursor, } from './view/invoicing/auditView/auditViewSelector';
725
726
  export { getCreateInvoiceFetchState, getCreateInvoiceFormView, getCreatedInvoiceId, } from './view/invoicing/createInvoice/createInvoiceSelector';
726
- export { getRecordPaymentFetchState, getRecordedTransactionId, } from './view/invoicing/recordPayment/recordPaymentSelector';
727
+ export { getRecordPaymentFetchState, getRecordPaymentFormView, getRecordedTransactionId, } from './view/invoicing/recordPayment/recordPaymentSelector';
727
728
  export { initializeInvoicingCustomerAddress, resetEditInvoicingCustomerDetailView, submitInvoicingCustomerForm, submitInvoicingCustomerFormFailure, submitInvoicingCustomerFormSuccess, updateInvoicingCustomerFormDraft, } from './view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer';
728
729
  export { INVOICING_CUSTOMER_BILLING_ADDRESS_TYPE, INVOICING_CUSTOMER_TYPE_VALUES, INVOICING_NET_TERM_DAY_VALUES, INVOICING_TAXABILITY_VALUES, entityToInvoicingCustomerFormLocalData, initialInvoicingCustomerFormLocalData, } from './view/invoicing/editInvoicingCustomerDetailView/invoicingCustomerFormConfig';
729
730
  export { getInvoicingCustomerFormView } from './view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector';
730
731
  export { fetchInvoicingSubscriptionFormPage, initializeInvoicingSubscriptionAddress, resetEditInvoicingSubscriptionDetailView, submitInvoicingSubscriptionForm, updateInvoicingSubscriptionFormDraft, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer';
731
732
  export { INVOICING_SUBSCRIPTION_BILLING_FREQUENCY_VALUES, INVOICING_SUBSCRIPTION_SHIPPING_ADDRESS_TYPE, entityToInvoicingSubscriptionFormLocalData, initialInvoicingSubscriptionFormLocalData, } from './view/invoicing/editInvoicingSubscriptionDetailView/invoicingSubscriptionFormConfig';
732
733
  export { getEditInvoicingSubscriptionDetailViewState, getInvoicingSubscriptionFormView, } from './view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector';
733
- export { resetEditInvoicingCatalogItemDetailView, saveInvoicingCatalogItem, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer';
734
+ export { resetEditInvoicingCatalogItemDetailView, saveInvoicingCatalogItem, submitInvoicingCatalogItemForm, updateInvoicingCatalogItemFormDraft, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer';
735
+ export { blankInvoicingCatalogSubFamily, blankInvoicingCatalogTier, entityToInvoicingCatalogItemFormLocalData, initialInvoicingCatalogItemFormLocalData, isTieredCatalogPricingModel, } from './view/invoicing/editInvoicingCatalogItemDetailView/invoicingCatalogItemFormConfig';
734
736
  export { getEditInvoicingCatalogItemDetailViewState, getInvoicingCatalogItemFormView, getSavedInvoicingCatalogItemId, getSavedInvoicingCatalogItemKind, } from './view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector';
735
- export { resetEditInvoicingCouponDetailView, saveInvoicingCoupon, } from './view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer';
737
+ export { resetEditInvoicingCouponDetailView, saveInvoicingCoupon, submitInvoicingCouponForm, updateInvoicingCouponFormDraft, } from './view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer';
738
+ export { entityToInvoicingCouponFormLocalData, initialInvoicingCouponFormLocalData, } from './view/invoicing/editInvoicingCouponDetailView/invoicingCouponFormConfig';
736
739
  export { getEditInvoicingCouponDetailViewState, getInvoicingCouponFormView, } from './view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector';
737
740
  export { clearInvoicingInvoiceAction, runInvoicingInvoiceAction, updateInvoicingInvoice, } from './view/invoicing/invoiceAction/invoiceActionReducer';
738
741
  export { getInvoicingInvoiceActionState } from './view/invoicing/invoiceAction/invoiceActionSelector';
@@ -1 +1,137 @@
1
- export {};
1
+ import { blankInvoicingCatalogSubFamily, isTieredCatalogPricingModel, } from './invoicingCatalogItemFormConfig';
2
+ const CURRENCY_CODE = 'USD';
3
+ const trimOrUndefined = (value) => value.trim() !== '' ? value.trim() : undefined;
4
+ const toAmountValue = (value) => Number(value) || 0;
5
+ const buildAccountingDetail = (localData) => {
6
+ const detail = {};
7
+ if (localData.sku.trim() !== '') {
8
+ detail.sku = localData.sku.trim();
9
+ }
10
+ if (localData.accountingCode.trim() !== '') {
11
+ detail.accounting_code = localData.accountingCode.trim();
12
+ }
13
+ if (localData.accountingCategory.trim() !== '') {
14
+ detail.accounting_category_1 = localData.accountingCategory.trim();
15
+ }
16
+ return Object.keys(detail).length > 0 ? detail : undefined;
17
+ };
18
+ const buildSubFamilyPayload = (localData, subFamily, subFamilyId) => {
19
+ const isCharge = localData.catalogType === 'charge';
20
+ const isAddon = localData.catalogType === 'addon';
21
+ const tiered = isTieredCatalogPricingModel(subFamily.pricingModel);
22
+ const resolvedName = trimOrUndefined(subFamily.externalName) ??
23
+ trimOrUndefined(localData.invoiceName) ??
24
+ `${localData.name.trim()} ${CURRENCY_CODE}${subFamily.periodUnit ? ` ${subFamily.periodUnit}` : ''}`;
25
+ const payload = {
26
+ currency_code: CURRENCY_CODE,
27
+ free_quantity: Number(subFamily.freeQuantity) || 0,
28
+ id: subFamilyId,
29
+ is_taxable: subFamily.isTaxable,
30
+ item_type: isCharge ? 'charge' : isAddon ? 'addon' : 'plan',
31
+ name: resolvedName,
32
+ price: tiered ? 0 : toAmountValue(subFamily.priceDollars),
33
+ pricing_model: subFamily.pricingModel,
34
+ show_description_in_invoices: subFamily.showDescriptionInInvoices,
35
+ show_description_in_quotes: subFamily.showDescriptionInQuotes,
36
+ };
37
+ const externalName = trimOrUndefined(subFamily.externalName);
38
+ if (externalName != null) {
39
+ payload.external_name = externalName;
40
+ }
41
+ const description = trimOrUndefined(subFamily.description);
42
+ if (description != null) {
43
+ payload.description = description;
44
+ }
45
+ if (subFamily.period.trim() !== '') {
46
+ payload.period = Number(subFamily.period);
47
+ payload.period_unit = subFamily.periodUnit || 'month';
48
+ }
49
+ if (subFamily.trialPeriod.trim() !== '') {
50
+ payload.trial_period = Number(subFamily.trialPeriod);
51
+ payload.trial_period_unit = subFamily.trialPeriodUnit;
52
+ payload.trial_end_action = subFamily.trialEndAction;
53
+ }
54
+ if (subFamily.billingCycles.trim() !== '') {
55
+ payload.billing_cycles = Number(subFamily.billingCycles);
56
+ }
57
+ if (isAddon && subFamily.prorationType) {
58
+ payload.proration_type = subFamily.prorationType;
59
+ }
60
+ const notes = trimOrUndefined(localData.invoiceNotes);
61
+ if (notes != null) {
62
+ payload.invoice_notes = notes;
63
+ }
64
+ if (tiered) {
65
+ payload.tiers = subFamily.tiers.map((tier) => ({
66
+ ending_unit: tier.endingUnit.trim() !== '' ? Number(tier.endingUnit) : undefined,
67
+ package_size: tier.packageSize.trim() !== '' ? Number(tier.packageSize) : undefined,
68
+ price: toAmountValue(tier.price),
69
+ pricing_type: tier.pricingType,
70
+ starting_unit: Number(tier.startingUnit) || 1,
71
+ }));
72
+ }
73
+ const accountingDetail = buildAccountingDetail(localData);
74
+ if (accountingDetail != null) {
75
+ payload.accounting_detail = accountingDetail;
76
+ }
77
+ return payload;
78
+ };
79
+ /**
80
+ * Build the create/update catalog-item request body from the form draft. Plans
81
+ * are sent with nested `sub_family_details`; add-ons / one-time charges flatten
82
+ * the first sub-family onto the item payload. Ports the web-c form's builder.
83
+ */
84
+ export const localDataToSaveInvoicingCatalogItemPayload = (localData, isCreate) => {
85
+ const isPlan = localData.catalogType === 'plan';
86
+ const itemPayload = {
87
+ currency_code: CURRENCY_CODE,
88
+ enabled_for_checkout: true,
89
+ enabled_in_portal: true,
90
+ is_giftable: false,
91
+ is_shippable: false,
92
+ item_applicability: localData.itemApplicability,
93
+ metered: false,
94
+ name: localData.name.trim(),
95
+ type: isPlan ? 'plan' : 'product',
96
+ };
97
+ if (isCreate) {
98
+ itemPayload.id = localData.itemId.trim();
99
+ }
100
+ const externalName = trimOrUndefined(localData.externalName);
101
+ if (externalName != null) {
102
+ itemPayload.externalName = externalName;
103
+ }
104
+ const description = trimOrUndefined(localData.description);
105
+ if (description != null) {
106
+ itemPayload.description = description;
107
+ }
108
+ const unit = trimOrUndefined(localData.unit);
109
+ if (unit != null) {
110
+ itemPayload.unit = unit;
111
+ }
112
+ if (localData.itemApplicability === 'restricted' &&
113
+ localData.applicableItems.length > 0) {
114
+ itemPayload.applicableItems = localData.applicableItems;
115
+ }
116
+ if (isPlan) {
117
+ const planId = localData.itemId.trim();
118
+ const usedIds = new Set();
119
+ const subFamilyDetails = localData.subFamilies.map((subFamily, index) => {
120
+ let subFamilyId = `${planId}-${CURRENCY_CODE.toLowerCase()}` +
121
+ (subFamily.period
122
+ ? `-${subFamily.period}${subFamily.periodUnit.charAt(0)}`
123
+ : '');
124
+ if (usedIds.has(subFamilyId)) {
125
+ subFamilyId = `${subFamilyId}-${index + 1}`;
126
+ }
127
+ usedIds.add(subFamilyId);
128
+ return buildSubFamilyPayload(localData, subFamily, subFamilyId);
129
+ });
130
+ return { ...itemPayload, sub_family_details: subFamilyDetails };
131
+ }
132
+ const subFamily = localData.subFamilies[0] ?? blankInvoicingCatalogSubFamily();
133
+ const subFamilyPayload = buildSubFamilyPayload(localData, subFamily, localData.itemId.trim());
134
+ delete subFamilyPayload.id;
135
+ delete subFamilyPayload.name;
136
+ return { ...itemPayload, ...subFamilyPayload };
137
+ };
@@ -1,8 +1,10 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
+ import { initialInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormConfig';
2
3
  export const initialState = {
3
4
  fetchState: 'Not-Started',
4
5
  error: undefined,
5
- data: undefined,
6
+ editDraftById: {},
7
+ newItemDraft: { ...initialInvoicingCatalogItemFormLocalData },
6
8
  savedItemId: undefined,
7
9
  savedKind: undefined,
8
10
  hasValidState() {
@@ -13,27 +15,50 @@ const editInvoicingCatalogItemDetailView = createSlice({
13
15
  name: 'editInvoicingCatalogItemDetailView',
14
16
  initialState,
15
17
  reducers: {
18
+ updateInvoicingCatalogItemFormDraft(draft, action) {
19
+ const { id, localData } = action.payload;
20
+ if (id != null) {
21
+ draft.editDraftById[id] = localData;
22
+ }
23
+ else {
24
+ draft.newItemDraft = localData;
25
+ }
26
+ },
27
+ submitInvoicingCatalogItemForm: {
28
+ reducer(draft) {
29
+ draft.fetchState = 'In-Progress';
30
+ draft.error = undefined;
31
+ draft.savedItemId = undefined;
32
+ },
33
+ prepare(payload) {
34
+ return { payload };
35
+ },
36
+ },
16
37
  saveInvoicingCatalogItem(draft, action) {
17
38
  draft.fetchState = 'In-Progress';
18
39
  draft.error = undefined;
19
40
  draft.savedItemId = undefined;
20
41
  draft.savedKind = action.payload.kind;
21
- draft.data = action.payload.data;
22
42
  },
23
- saveInvoicingCatalogItemSuccess(draft, action) {
43
+ submitInvoicingCatalogItemFormSuccess(draft, action) {
24
44
  draft.fetchState = 'Completed';
25
45
  draft.error = undefined;
26
46
  draft.savedItemId = action.payload.itemId;
27
47
  draft.savedKind = action.payload.kind;
28
48
  },
29
- saveInvoicingCatalogItemFailure(draft, action) {
49
+ submitInvoicingCatalogItemFormFailure(draft, action) {
30
50
  draft.fetchState = 'Error';
31
51
  draft.error = action.payload;
32
52
  },
33
53
  resetEditInvoicingCatalogItemDetailView(draft) {
34
- Object.assign(draft, initialState);
54
+ draft.fetchState = 'Not-Started';
55
+ draft.error = undefined;
56
+ draft.savedItemId = undefined;
57
+ draft.savedKind = undefined;
58
+ draft.editDraftById = {};
59
+ draft.newItemDraft = { ...initialInvoicingCatalogItemFormLocalData };
35
60
  },
36
61
  },
37
62
  });
38
- export const { saveInvoicingCatalogItem, saveInvoicingCatalogItemSuccess, saveInvoicingCatalogItemFailure, resetEditInvoicingCatalogItemDetailView, } = editInvoicingCatalogItemDetailView.actions;
63
+ export const { updateInvoicingCatalogItemFormDraft, submitInvoicingCatalogItemForm, saveInvoicingCatalogItem, submitInvoicingCatalogItemFormSuccess, submitInvoicingCatalogItemFormFailure, resetEditInvoicingCatalogItemDetailView, } = editInvoicingCatalogItemDetailView.actions;
39
64
  export default editInvoicingCatalogItemDetailView.reducer;
@@ -1,5 +1,6 @@
1
1
  import { getInvoicingPlanById } from '../../../entity/invoicing/plan/planSelector';
2
2
  import { getInvoicingProductById } from '../../../entity/invoicing/product/productSelector';
3
+ import { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PERIOD_UNIT_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, INVOICING_CATALOG_TRIAL_END_ACTION_VALUES, INVOICING_CATALOG_TRIAL_UNIT_VALUES, INVOICING_CATALOG_TYPE_VALUES, entityToInvoicingCatalogItemFormLocalData, } from './invoicingCatalogItemFormConfig';
3
4
  export const getEditInvoicingCatalogItemDetailViewState = (state) => ({
4
5
  fetchState: state.editInvoicingCatalogItemDetailViewState.fetchState,
5
6
  error: state.editInvoicingCatalogItemDetailViewState.error,
@@ -7,14 +8,30 @@ export const getEditInvoicingCatalogItemDetailViewState = (state) => ({
7
8
  export const getSavedInvoicingCatalogItemId = (state) => state.editInvoicingCatalogItemDetailViewState.savedItemId;
8
9
  export const getSavedInvoicingCatalogItemKind = (state) => state.editInvoicingCatalogItemDetailViewState.savedKind;
9
10
  export const getInvoicingCatalogItemFormView = (state, kind, id) => {
10
- const { error, fetchState, savedItemId, savedKind } = state.editInvoicingCatalogItemDetailViewState;
11
+ const { editDraftById, error, fetchState, newItemDraft, savedItemId, savedKind } = state.editInvoicingCatalogItemDetailViewState;
12
+ const plan = kind === 'plan' && id != null
13
+ ? getInvoicingPlanById(state.invoicingPlanState, id)
14
+ : undefined;
15
+ const product = kind === 'product' && id != null
16
+ ? getInvoicingProductById(state.invoicingProductState, id)
17
+ : undefined;
18
+ const localData = id != null
19
+ ? (editDraftById[id] ??
20
+ entityToInvoicingCatalogItemFormLocalData(plan ?? product, kind))
21
+ : newItemDraft;
11
22
  return {
12
- plan: kind === 'plan' && id != null
13
- ? getInvoicingPlanById(state.invoicingPlanState, id)
14
- : undefined,
15
- product: kind === 'product' && id != null
16
- ? getInvoicingProductById(state.invoicingProductState, id)
17
- : undefined,
23
+ applicabilityValues: [...INVOICING_CATALOG_APPLICABILITY_VALUES],
24
+ localData,
25
+ mode: id != null ? 'edit' : 'create',
26
+ periodUnitValues: [...INVOICING_CATALOG_PERIOD_UNIT_VALUES],
27
+ pricingModelValues: [...INVOICING_CATALOG_PRICING_MODEL_VALUES],
28
+ prorationValues: [...INVOICING_CATALOG_PRORATION_VALUES],
29
+ tierTypeValues: [...INVOICING_CATALOG_TIER_TYPE_VALUES],
30
+ trialEndActionValues: [...INVOICING_CATALOG_TRIAL_END_ACTION_VALUES],
31
+ trialUnitValues: [...INVOICING_CATALOG_TRIAL_UNIT_VALUES],
32
+ typeValues: [...INVOICING_CATALOG_TYPE_VALUES],
33
+ plan,
34
+ product,
18
35
  savedItemId,
19
36
  savedKind,
20
37
  fetchState,
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Canonical value sets for the catalog item form. CES owns the values;
3
+ * web-components maps each value to a localized label.
4
+ */
5
+ export const INVOICING_CATALOG_TYPE_VALUES = [
6
+ 'plan',
7
+ 'addon',
8
+ 'charge',
9
+ ];
10
+ export const INVOICING_CATALOG_PERIOD_UNIT_VALUES = [
11
+ 'day',
12
+ 'week',
13
+ 'month',
14
+ 'year',
15
+ ];
16
+ export const INVOICING_CATALOG_PRICING_MODEL_VALUES = [
17
+ 'flat_fee',
18
+ 'per_unit',
19
+ 'tiered',
20
+ 'volume',
21
+ 'stairstep',
22
+ ];
23
+ export const INVOICING_CATALOG_TIER_TYPE_VALUES = [
24
+ 'per_unit',
25
+ 'flat_fee',
26
+ 'package',
27
+ ];
28
+ export const INVOICING_CATALOG_TRIAL_UNIT_VALUES = ['day', 'month'];
29
+ export const INVOICING_CATALOG_TRIAL_END_ACTION_VALUES = [
30
+ 'site_default',
31
+ 'activate_subscription',
32
+ 'cancel_subscription',
33
+ ];
34
+ export const INVOICING_CATALOG_PRORATION_VALUES = [
35
+ 'site_default',
36
+ 'partial_term',
37
+ 'full_term',
38
+ ];
39
+ export const INVOICING_CATALOG_APPLICABILITY_VALUES = [
40
+ 'all',
41
+ 'restricted',
42
+ ];
43
+ export const isTieredCatalogPricingModel = (model) => ['tiered', 'volume', 'stairstep'].includes(model);
44
+ export const blankInvoicingCatalogTier = (startingUnit = '1') => ({
45
+ endingUnit: '',
46
+ packageSize: '',
47
+ price: '',
48
+ pricingType: 'per_unit',
49
+ startingUnit,
50
+ });
51
+ export const blankInvoicingCatalogSubFamily = () => ({
52
+ billingCycles: '',
53
+ description: '',
54
+ externalName: '',
55
+ freeQuantity: '0',
56
+ isTaxable: true,
57
+ period: '1',
58
+ periodUnit: 'month',
59
+ priceDollars: '',
60
+ pricingModel: 'flat_fee',
61
+ prorationType: 'site_default',
62
+ showDescriptionInInvoices: true,
63
+ showDescriptionInQuotes: true,
64
+ tiers: [blankInvoicingCatalogTier('1')],
65
+ trialEndAction: 'site_default',
66
+ trialPeriod: '',
67
+ trialPeriodUnit: 'month',
68
+ });
69
+ const subFamilyFromProduct = (product) => {
70
+ const base = blankInvoicingCatalogSubFamily();
71
+ if (product == null) {
72
+ return base;
73
+ }
74
+ return {
75
+ ...base,
76
+ billingCycles: product.billingCycles != null ? String(product.billingCycles) : '',
77
+ description: product.description ?? '',
78
+ externalName: product.externalName ?? '',
79
+ freeQuantity: product.freeQuantity != null ? String(product.freeQuantity) : '0',
80
+ isTaxable: product.isTaxable ?? true,
81
+ period: product.period != null ? String(product.period) : '1',
82
+ periodUnit: product.periodUnit ?? 'month',
83
+ priceDollars: product.price != null ? String(product.price.amount) : '',
84
+ pricingModel: product.pricingModel ?? 'flat_fee',
85
+ prorationType: product.prorationType ?? 'site_default',
86
+ showDescriptionInInvoices: product.showDescriptionInInvoices ?? true,
87
+ showDescriptionInQuotes: product.showDescriptionInQuotes ?? true,
88
+ tiers: product.tiers != null && product.tiers.length > 0
89
+ ? product.tiers.map((tier) => ({
90
+ endingUnit: tier.endingUnit != null ? String(tier.endingUnit) : '',
91
+ packageSize: tier.packageSize != null ? String(tier.packageSize) : '',
92
+ price: String(tier.price.amount),
93
+ pricingType: tier.pricingType ?? 'per_unit',
94
+ startingUnit: String(tier.startingUnit ?? 1),
95
+ }))
96
+ : [blankInvoicingCatalogTier('1')],
97
+ trialEndAction: product.trialEndAction ?? 'site_default',
98
+ trialPeriod: product.trialPeriod != null ? String(product.trialPeriod) : '',
99
+ trialPeriodUnit: product.trialPeriodUnit ?? 'month',
100
+ };
101
+ };
102
+ export const initialInvoicingCatalogItemFormLocalData = {
103
+ accountingCategory: '',
104
+ accountingCode: '',
105
+ applicableItems: [],
106
+ catalogType: 'plan',
107
+ description: '',
108
+ externalName: '',
109
+ invoiceName: '',
110
+ invoiceNotes: '',
111
+ itemApplicability: 'all',
112
+ itemId: '',
113
+ name: '',
114
+ sku: '',
115
+ subFamilies: [blankInvoicingCatalogSubFamily()],
116
+ unit: '',
117
+ };
118
+ /**
119
+ * Seed the form draft from an existing plan/product entity (edit mode). Mirrors
120
+ * the web-c form: product-specific pricing/accounting fields only populate for
121
+ * the `product` kind; a plan starts with a single blank sub-family.
122
+ */
123
+ export const entityToInvoicingCatalogItemFormLocalData = (item, kind) => {
124
+ if (item == null) {
125
+ return {
126
+ ...initialInvoicingCatalogItemFormLocalData,
127
+ subFamilies: [blankInvoicingCatalogSubFamily()],
128
+ };
129
+ }
130
+ const product = kind === 'product' ? item : undefined;
131
+ const catalogType = kind === 'product'
132
+ ? product?.itemType === 'charge'
133
+ ? 'charge'
134
+ : 'addon'
135
+ : 'plan';
136
+ return {
137
+ accountingCategory: product?.accountingDetail?.accountingCategory1 ?? '',
138
+ accountingCode: product?.accountingDetail?.accountingCode ?? '',
139
+ applicableItems: item.applicableItems ?? [],
140
+ catalogType,
141
+ description: item.description ?? '',
142
+ externalName: item.externalName ?? '',
143
+ invoiceName: product?.name ?? '',
144
+ invoiceNotes: product?.invoiceNotes ?? '',
145
+ itemApplicability: item.itemApplicability ?? 'all',
146
+ itemId: item.id ?? '',
147
+ name: item.name ?? '',
148
+ sku: product?.accountingDetail?.sku ?? '',
149
+ subFamilies: [subFamilyFromProduct(product)],
150
+ unit: item.unit ?? '',
151
+ };
152
+ };
@@ -3,9 +3,25 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { updateInvoicingPlans } from '../../../entity/invoicing/plan/planReducer';
4
4
  import { updateInvoicingProducts } from '../../../entity/invoicing/product/productReducer';
5
5
  import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
6
- import { saveInvoicingCatalogItem, saveInvoicingCatalogItemFailure, saveInvoicingCatalogItemSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
7
- export const saveInvoicingCatalogItemEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(saveInvoicingCatalogItem.match), mergeMap((action) => {
8
- const { data, id, kind } = action.payload;
6
+ import { localDataToSaveInvoicingCatalogItemPayload, } from './editInvoicingCatalogItemDetailViewPayload';
7
+ import { saveInvoicingCatalogItem, submitInvoicingCatalogItemForm, submitInvoicingCatalogItemFormFailure, submitInvoicingCatalogItemFormSuccess, } from './editInvoicingCatalogItemDetailViewReducer';
8
+ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => submitInvoicingCatalogItemForm.match(action) ||
9
+ saveInvoicingCatalogItem.match(action)), mergeMap((action) => {
10
+ const { id } = action.payload;
11
+ // Draft-based create/edit form vs. detail-page inline edit (raw data).
12
+ let kind;
13
+ let data;
14
+ if (saveInvoicingCatalogItem.match(action)) {
15
+ kind = action.payload.kind;
16
+ data = action.payload.data;
17
+ }
18
+ else {
19
+ const viewState = state$.value.editInvoicingCatalogItemDetailViewState;
20
+ const localData = (id != null ? viewState.editDraftById[id] : viewState.newItemDraft) ??
21
+ viewState.newItemDraft;
22
+ kind = localData.catalogType === 'plan' ? 'plan' : 'product';
23
+ data = localDataToSaveInvoicingCatalogItemPayload(localData, id == null);
24
+ }
9
25
  const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
10
26
  const collection = kind === 'plan' ? 'plans' : 'products';
11
27
  const path = id != null
@@ -25,13 +41,13 @@ export const saveInvoicingCatalogItemEpic = (actions$, _state$, zeniAPI) => acti
25
41
  : updateInvoicingProducts([response.data], 'merge');
26
42
  return [
27
43
  entityAction,
28
- saveInvoicingCatalogItemSuccess({
44
+ submitInvoicingCatalogItemFormSuccess({
29
45
  itemId: response.data.id,
30
46
  kind,
31
47
  }),
32
48
  ];
33
49
  }
34
- return of(saveInvoicingCatalogItemFailure(response.status));
35
- }), catchError((error) => of(saveInvoicingCatalogItemFailure(createZeniAPIStatus('Unexpected Error', 'Save catalog item REST API call errored out ' +
50
+ return of(submitInvoicingCatalogItemFormFailure(response.status));
51
+ }), catchError((error) => of(submitInvoicingCatalogItemFormFailure(createZeniAPIStatus('Unexpected Error', 'Save catalog item REST API call errored out ' +
36
52
  JSON.stringify(error))))));
37
53
  }));
@@ -1 +1,59 @@
1
- export {};
1
+ /**
2
+ * Build the create/update discount request body from the form draft (snake_case
3
+ * matching the `/discounts` schema). On create the coupon id is part of the
4
+ * body; on edit it is the URL param, so it is omitted here.
5
+ */
6
+ export const localDataToSaveInvoicingCouponPayload = (localData, isCreate) => {
7
+ const data = {
8
+ apply_on: localData.applyOn,
9
+ discount_type: localData.discountType,
10
+ duration_type: localData.durationType,
11
+ name: localData.name.trim(),
12
+ status: 'active',
13
+ };
14
+ if (isCreate) {
15
+ data.id = localData.couponId.trim();
16
+ }
17
+ const couponCode = localData.couponCode.trim();
18
+ if (couponCode !== '') {
19
+ data.coupon_code = couponCode;
20
+ }
21
+ if (localData.discountType === 'percentage' &&
22
+ localData.discountPercentage.trim() !== '') {
23
+ data.discount_percentage = Number(localData.discountPercentage);
24
+ }
25
+ if (localData.discountType === 'fixed_amount') {
26
+ if (localData.discountAmount.trim() !== '') {
27
+ data.discount_amount = Number(localData.discountAmount);
28
+ }
29
+ data.currency_code = 'USD';
30
+ }
31
+ if (localData.discountType === 'offer_quantity' &&
32
+ localData.discountQuantity.trim() !== '') {
33
+ data.discount_quantity = Number(localData.discountQuantity);
34
+ }
35
+ if (localData.durationType === 'limited_period') {
36
+ if (localData.period.trim() !== '') {
37
+ data.period = Number(localData.period);
38
+ }
39
+ data.period_unit = localData.periodUnit;
40
+ }
41
+ if (localData.validFrom.trim() !== '') {
42
+ data.valid_from = localData.validFrom.trim();
43
+ }
44
+ if (localData.validTill.trim() !== '') {
45
+ data.valid_till = localData.validTill.trim();
46
+ }
47
+ if (localData.maxRedemptions.trim() !== '') {
48
+ data.max_redemptions = Number(localData.maxRedemptions);
49
+ }
50
+ const invoiceName = localData.invoiceName.trim();
51
+ if (invoiceName !== '') {
52
+ data.invoice_name = invoiceName;
53
+ }
54
+ const invoiceNotes = localData.invoiceNotes.trim();
55
+ if (invoiceNotes !== '') {
56
+ data.invoice_notes = invoiceNotes;
57
+ }
58
+ return data;
59
+ };
@@ -1,8 +1,10 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
+ import { initialInvoicingCouponFormLocalData } from './invoicingCouponFormConfig';
2
3
  export const initialState = {
3
4
  fetchState: 'Not-Started',
4
5
  error: undefined,
5
- data: undefined,
6
+ editDraftById: {},
7
+ newCouponDraft: { ...initialInvoicingCouponFormLocalData },
6
8
  savedCouponId: undefined,
7
9
  hasValidState() {
8
10
  return this.fetchState === 'Completed';
@@ -12,25 +14,52 @@ const editInvoicingCouponDetailView = createSlice({
12
14
  name: 'editInvoicingCouponDetailView',
13
15
  initialState,
14
16
  reducers: {
15
- saveInvoicingCoupon(draft, action) {
16
- draft.fetchState = 'In-Progress';
17
- draft.error = undefined;
18
- draft.savedCouponId = undefined;
19
- draft.data = action.payload.data;
17
+ updateInvoicingCouponFormDraft(draft, action) {
18
+ const { id, localData } = action.payload;
19
+ if (id != null) {
20
+ draft.editDraftById[id] = localData;
21
+ }
22
+ else {
23
+ draft.newCouponDraft = localData;
24
+ }
25
+ },
26
+ submitInvoicingCouponForm: {
27
+ reducer(draft) {
28
+ draft.fetchState = 'In-Progress';
29
+ draft.error = undefined;
30
+ draft.savedCouponId = undefined;
31
+ },
32
+ prepare(payload) {
33
+ return { payload };
34
+ },
20
35
  },
21
- saveInvoicingCouponSuccess(draft, action) {
36
+ saveInvoicingCoupon: {
37
+ reducer(draft) {
38
+ draft.fetchState = 'In-Progress';
39
+ draft.error = undefined;
40
+ draft.savedCouponId = undefined;
41
+ },
42
+ prepare(payload) {
43
+ return { payload };
44
+ },
45
+ },
46
+ submitInvoicingCouponFormSuccess(draft, action) {
22
47
  draft.fetchState = 'Completed';
23
48
  draft.error = undefined;
24
49
  draft.savedCouponId = action.payload.couponId;
25
50
  },
26
- saveInvoicingCouponFailure(draft, action) {
51
+ submitInvoicingCouponFormFailure(draft, action) {
27
52
  draft.fetchState = 'Error';
28
53
  draft.error = action.payload;
29
54
  },
30
55
  resetEditInvoicingCouponDetailView(draft) {
31
- Object.assign(draft, initialState);
56
+ draft.fetchState = 'Not-Started';
57
+ draft.error = undefined;
58
+ draft.savedCouponId = undefined;
59
+ draft.editDraftById = {};
60
+ draft.newCouponDraft = { ...initialInvoicingCouponFormLocalData };
32
61
  },
33
62
  },
34
63
  });
35
- export const { saveInvoicingCoupon, saveInvoicingCouponSuccess, saveInvoicingCouponFailure, resetEditInvoicingCouponDetailView, } = editInvoicingCouponDetailView.actions;
64
+ export const { updateInvoicingCouponFormDraft, submitInvoicingCouponForm, saveInvoicingCoupon, submitInvoicingCouponFormSuccess, submitInvoicingCouponFormFailure, resetEditInvoicingCouponDetailView, } = editInvoicingCouponDetailView.actions;
36
65
  export default editInvoicingCouponDetailView.reducer;