Skip to content

Commit f8ed529

Browse files
yuryyasGFilipovich
authored andcommitted
OD-19403 Refactored membership expiry calculation
1 parent 7d03cbf commit f8ed529

File tree

9 files changed

+63
-64
lines changed

9 files changed

+63
-64
lines changed

client-html/src/js/common/components/form/formFields/FormEditor.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ const FormEditor: React.FC<Props & WrappedFieldProps> = (
367367
component="div"
368368
onClick={onEditButtonFocus}
369369
className={clsx(classes.editable, {
370-
[fieldClasses.text]: value
370+
[fieldClasses.text]: value,
371+
'pointer-events-none': disabled
371372
})}
372373
>
373374
<span

client-html/src/js/containers/checkout/actions/chekoutItem.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ export const checkoutGetProduct = (id: number) => ({
2929
payload: id
3030
});
3131

32-
export const checkoutGetMembership = (item: CheckoutItem) => ({
32+
export const checkoutGetMembership = (id: number) => ({
3333
type: CHECKOUT_GET_ITEM_MEMBERSHIP,
34-
payload: item
34+
payload: { id }
3535
});
3636

3737
export const checkoutGetVoucher = (item: CheckoutItem) => ({

client-html/src/js/containers/checkout/components/CheckoutSelection.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ const mapDispatchToProps = (dispatch: Dispatch<any>) => ({
13191319
removeItem: (itemId: number, itemType: string) => dispatch(removeItem(itemId, itemType)),
13201320
checkoutGetCourseClassList: (search: string) => dispatch(checkoutGetCourseClassList(search)),
13211321
checkoutClearCourseClassList: () => dispatch(checkoutClearCourseClassList()),
1322-
getMemberShipRecord: (item: any) => dispatch(checkoutGetMembership(item)),
1322+
getMemberShipRecord: (item: any) => dispatch(checkoutGetMembership(item.id)),
13231323
getProductRecord: (id: number) => dispatch(checkoutGetProduct(id)),
13241324
getVoucherRecord: (item: any) => dispatch(checkoutGetVoucher(item)),
13251325
clearItemRecord: () => {

client-html/src/js/containers/checkout/components/items/components/MembershipEditView.tsx

+20-26
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,32 @@
33
* No copying or use of this code is allowed without permission in writing from ish.
44
*/
55

6+
import { CheckoutMembershipProduct } from "@api/model";
67
import Grid from "@mui/material/Grid";
78
import { format as formatDate } from "date-fns";
89
import { III_DD_MMM_YYYY } from "ish-ui";
910
import React from "react";
11+
import { FormEditorField } from "../../../../../common/components/form/formFields/FormEditor";
1012
import Uneditable from "../../../../../common/components/form/formFields/Uneditable";
1113

12-
const MembershipEditView: React.FC<any> = props => {
13-
const { values } = props;
14-
15-
return values ? (
16-
<Grid container columnSpacing={3} rowSpacing={2} className="ml-0">
17-
<Grid item xs={2}>
18-
<Uneditable label="SKU" value={values.code} />
19-
</Grid>
20-
<Grid item xs={8}>
21-
<Uneditable label="Sale price" value={values.totalFee} money />
22-
</Grid>
23-
24-
<Grid item xs={6}>
25-
<Uneditable label="Description" value={values.description} multiline />
26-
</Grid>
27-
<Grid item xs={6}>
28-
{values.validTo && (
29-
<Uneditable label="Expires on" value={values.validTo} format={v => formatDate(new Date(v), III_DD_MMM_YYYY)} />
30-
)}
31-
{values.expireNever && (
32-
<Uneditable label="Expires on" value={values.expireNever} />
33-
)}
34-
</Grid>
35-
14+
const MembershipEditView = ({ values }: { values: CheckoutMembershipProduct }) => values ? (
15+
<Grid container columnSpacing={3} rowSpacing={2} className="ml-0">
16+
<Grid item xs={4}>
17+
<Uneditable label="SKU" value={values.code} />
18+
</Grid>
19+
<Grid item xs={4}>
20+
<Uneditable label="Sale price" value={values.totalFee} money />
21+
</Grid>
22+
<Grid item xs={4}>
23+
<Uneditable label="Expires on" {...values.expiresOn
24+
? { value: values.expiresOn, format: v => formatDate(new Date(v), III_DD_MMM_YYYY) }
25+
: { value: "Never (Lifetime)" }
26+
} />
27+
</Grid>
28+
<Grid item xs={12}>
29+
<FormEditorField label="Description" name="description" disabled />
3630
</Grid>
37-
) : null;
38-
};
31+
</Grid>
32+
) : null;
3933

4034
export default MembershipEditView;

client-html/src/js/containers/checkout/epics/item/EpicCheckoutGetMembership.ts

+6-8
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,20 @@
33
* No copying or use of this code is allowed without permission in writing from ish.
44
*/
55

6+
import { CheckoutMembershipProduct } from "@api/model";
67
import { initialize } from "redux-form";
78
import { Epic } from "redux-observable";
89
import FetchErrorHandler from "../../../../common/api/fetch-errors-handlers/FetchErrorHandler";
910
import * as EpicUtils from "../../../../common/epics/EpicUtils";
10-
import { CheckoutItem } from "../../../../model/checkout";
11-
import { getEntityItemById } from "../../../entities/common/entityItemsService";
11+
import MembershipProductService
12+
from "../../../../containers/entities/membershipProducts/services/MembershipProductService";
1213
import { CHECKOUT_GET_ITEM_MEMBERSHIP, CHECKOUT_GET_ITEM_MEMBERSHIP_FULFILLED } from "../../actions/chekoutItem";
1314
import { CHECKOUT_ITEM_EDIT_VIEW_FORM } from "../../components/items/components/CkecoutItemViewForm";
1415

15-
const request: EpicUtils.Request<any, CheckoutItem> = {
16+
const request: EpicUtils.Request<CheckoutMembershipProduct, { id: number }> = {
1617
type: CHECKOUT_GET_ITEM_MEMBERSHIP,
17-
getData: ({ id }) => getEntityItemById("MembershipProduct", id),
18-
processData: (memberShipProduct: any, s, item) => {
19-
memberShipProduct.validTo = item.validTo;
20-
memberShipProduct.expiryType = item.expiryType;
21-
18+
getData: ({ id }, s) => MembershipProductService.getCheckoutModel(id, s.checkout.summary.list.find(c => c.payer)?.contact.id),
19+
processData: memberShipProduct => {
2220
return [
2321
{
2422
type: CHECKOUT_GET_ITEM_MEMBERSHIP_FULFILLED,

client-html/src/js/containers/checkout/epics/summary/EpicUpdateSummaryPrices.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ import {
1515
checkoutUpdateSummaryPrices
1616
} from "../../actions/checkoutSummary";
1717
import CheckoutService from "../../services/CheckoutService";
18-
import { getCheckoutModel } from "../../utils";
18+
import { getCheckoutModel, getCheckoutModelMembershipsValidTo } from "../../utils";
1919

2020
const request: EpicUtils.Request = {
2121
type: CHECKOUT_UPDATE_SUMMARY_PRICES,
2222
hideLoadIndicator: true,
23-
getData: (p, s) => {
23+
getData: async (p, s) => {
2424
const model = getCheckoutModel(s.checkout, [], null, {}, true);
25+
await getCheckoutModelMembershipsValidTo(model);
2526
return CheckoutService.checkoutSubmitPayment(
2627
model,
2728
true,

client-html/src/js/containers/checkout/utils/index.tsx

+18-22
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
CheckoutSummaryListItem
3030
} from "../../../model/checkout";
3131
import { CheckoutFundingInvoice } from "../../../model/checkout/fundingInvoice";
32+
import MembershipProductService from "../../entities/membershipProducts/services/MembershipProductService";
3233
import {
3334
CHECKOUT_MEMBERSHIP_COLUMNS,
3435
CHECKOUT_PRODUCT_COLUMNS,
@@ -187,6 +188,14 @@ export const mergeInvoicePaymentPlans = (paymentPlans: InvoicePaymentPlan[]) =>
187188
}));
188189
};
189190

191+
export const getCheckoutModelMembershipsValidTo = async (model: CheckoutModel) => {
192+
for (const node of model.contactNodes) {
193+
for (const mem of node.memberships) {
194+
mem.validTo = await MembershipProductService.getCheckoutModel(mem.productId, node.contactId).then(res => res.expiresOn);
195+
}
196+
}
197+
};
198+
190199
export const getCheckoutModel = (
191200
state: CheckoutState,
192201
paymentPlans: CheckoutPaymentPlan[],
@@ -358,6 +367,7 @@ export const getInvoiceLineKey = (entity: CheckoutEntity) => {
358367
};
359368

360369
const getInvoiceLinePrices = (item: CheckoutItem, lines: AbstractInvoiceLine[], itemOriginal: CheckoutItem) => {
370+
361371
const id = item.type === "course" && item.class ? item.class.id : item.id;
362372
const lineKey = getInvoiceLineKey(item.type);
363373
const targetLine = lines.find(l => l[lineKey] && (l[lineKey].productId === id || l[lineKey].classId === id));
@@ -401,10 +411,15 @@ const getInvoiceLinePrices = (item: CheckoutItem, lines: AbstractInvoiceLine[],
401411
price: 0
402412
};
403413

414+
const validTo = item.type === "membership" ? {
415+
validTo: lines[0]?.membership?.validTo
416+
} : {};
417+
404418
return {
405419
...item,
406420
...paymentPlansObj,
407-
...prices
421+
...prices,
422+
...validTo
408423
};
409424
};
410425

@@ -549,7 +564,7 @@ export const checkoutCourseMap = (courseBase, skipCheck?: boolean): CheckoutCour
549564
return course;
550565
};
551566

552-
export const calculateVoucherOrMembershipExpiry = (item: CheckoutItem) => {
567+
export const calculateVoucherExpiry = (item: CheckoutItem) => {
553568
switch (item.type) {
554569
case "voucher": {
555570
if (item.expiryDays) {
@@ -559,25 +574,6 @@ export const calculateVoucherOrMembershipExpiry = (item: CheckoutItem) => {
559574
}
560575
break;
561576
}
562-
case "membership": {
563-
if (item.expiryType === "Never (Lifetime)") {
564-
item.expireNever = item.expiryType;
565-
} else {
566-
if (item.expiryType === "Days") {
567-
const today = new Date();
568-
today.setDate(today.getDate() + Number(item.expiryDays));
569-
item.validTo = format(today, YYYY_MM_DD_MINUSED);
570-
}
571-
if (item.expiryType === "1st July") {
572-
const date = getExpireDate(6);
573-
item.validTo = format(date, YYYY_MM_DD_MINUSED);
574-
}
575-
if (item.expiryType === "1st January") {
576-
const date = getExpireDate(0);
577-
item.validTo = format(date, YYYY_MM_DD_MINUSED);
578-
}
579-
}
580-
}
581577
}
582578
};
583579

@@ -592,7 +588,7 @@ export const processCheckoutSale = (row, type) => {
592588
if ( type === "voucher") {
593589
row.restrictToPayer = false;
594590
}
595-
calculateVoucherOrMembershipExpiry(row);
591+
calculateVoucherExpiry(row);
596592
};
597593

598594
export const getCheckoutCurrentStep = (step: CheckoutCurrentStepType): number => {

client-html/src/js/containers/entities/membershipProducts/services/MembershipProductService.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
import { MembershipProduct, MembershipProductApi } from "@api/model";
1+
import { CheckoutMembershipProduct, MembershipProduct, MembershipProductApi } from "@api/model";
22
import { DefaultHttpService } from "../../../../common/services/HttpService";
33

44
class MembershipProductService {
55
readonly membershipProductApi = new MembershipProductApi(new DefaultHttpService());
66

7-
public getMembershipProduct(id: number): Promise<any> {
7+
public getMembershipProduct(id: number): Promise<MembershipProduct> {
88
return this.membershipProductApi.get(id);
99
}
1010

11+
public getCheckoutModel(id: number, contactId: number): Promise<CheckoutMembershipProduct> {
12+
return this.membershipProductApi.getCheckoutModel(id, contactId);
13+
}
14+
1115
public updateMembershipProduct(id: number, membershipProduct: MembershipProduct): Promise<any> {
1216
return this.membershipProductApi.update(id, membershipProduct);
1317
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package ish.oncourse.server.api.traits
2+
3+
trait CheckoutMembershipProductDTOTrait {
4+
5+
}

0 commit comments

Comments
 (0)