Skip to content

Commit 72a6e60

Browse files
committed
feat(promoCode): enhance discount logic and add tests for plan applicability
1 parent 0aa6738 commit 72a6e60

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

src/utils/promoCodeService.ts

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,15 @@ function isPlanApplicable(benefit: PromoCodeBenefit, plan: PlanModel): boolean {
182182
return benefit.applicablePlanIds.some((planId): boolean => planId.toString() === plan._id.toString());
183183
}
184184

185+
/**
186+
* Returns whether discount promo can affect plan price.
187+
*
188+
* @param plan - tariff plan
189+
*/
190+
function isDiscountablePlan(plan: PlanModel): boolean {
191+
return plan.monthlyCharge > 0 && isPlanAvailable(plan);
192+
}
193+
185194
/**
186195
* Calculates discounted price for one plan.
187196
*
@@ -190,7 +199,9 @@ function isPlanApplicable(benefit: PromoCodeBenefit, plan: PlanModel): boolean {
190199
*/
191200
export function calculatePromoCodePlanPrice(benefit: PromoCodeBenefit, plan: PlanModel): PromoCodePlanPrice {
192201
const originalAmount = plan.monthlyCharge;
193-
const isApplicable = benefit.type !== 'grant_plan' && isPlanAvailable(plan) && isPlanApplicable(benefit, plan);
202+
const isApplicable = benefit.type !== 'grant_plan' &&
203+
isDiscountablePlan(plan) &&
204+
isPlanApplicable(benefit, plan);
194205

195206
if (!isApplicable) {
196207
return {
@@ -208,6 +219,16 @@ export function calculatePromoCodePlanPrice(benefit: PromoCodeBenefit, plan: Pla
208219
const discountAmount = Math.floor(originalAmount * benefit.percent / 100);
209220
const finalAmount = Math.max(originalAmount - discountAmount, minFinalPrice);
210221

222+
if (finalAmount >= originalAmount) {
223+
return {
224+
planId: plan._id.toString(),
225+
isApplicable: false,
226+
originalAmount,
227+
finalAmount: originalAmount,
228+
discountAmount: 0,
229+
};
230+
}
231+
211232
return {
212233
planId: plan._id.toString(),
213234
isApplicable: true,
@@ -221,6 +242,16 @@ export function calculatePromoCodePlanPrice(benefit: PromoCodeBenefit, plan: Pla
221242
const minFinalPrice = benefit.minFinalPrice ?? DEFAULT_MIN_FINAL_PRICE;
222243
const finalAmount = Math.max(originalAmount - benefit.amount, minFinalPrice);
223244

245+
if (finalAmount >= originalAmount) {
246+
return {
247+
planId: plan._id.toString(),
248+
isApplicable: false,
249+
originalAmount,
250+
finalAmount: originalAmount,
251+
discountAmount: 0,
252+
};
253+
}
254+
224255
return {
225256
planId: plan._id.toString(),
226257
isApplicable: true,
@@ -231,12 +262,22 @@ export function calculatePromoCodePlanPrice(benefit: PromoCodeBenefit, plan: Pla
231262
}
232263

233264
case 'fixed_price':
265+
if (benefit.amount >= originalAmount) {
266+
return {
267+
planId: plan._id.toString(),
268+
isApplicable: false,
269+
originalAmount,
270+
finalAmount: originalAmount,
271+
discountAmount: 0,
272+
};
273+
}
274+
234275
return {
235276
planId: plan._id.toString(),
236277
isApplicable: true,
237278
originalAmount,
238279
finalAmount: benefit.amount,
239-
discountAmount: Math.max(originalAmount - benefit.amount, 0),
280+
discountAmount: originalAmount - benefit.amount,
240281
};
241282

242283
default:

test/utils/promoCodeService.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,35 @@ describe('PromoCodeService', () => {
122122
});
123123
});
124124

125+
it('does not apply discount promos to free plan', () => {
126+
const plan = createPlan({ monthlyCharge: 0 });
127+
const price = calculatePromoCodePlanPrice({
128+
type: 'percent_discount',
129+
percent: 20,
130+
} as any, plan);
131+
132+
expect(price).toMatchObject({
133+
isApplicable: false,
134+
originalAmount: 0,
135+
finalAmount: 0,
136+
discountAmount: 0,
137+
});
138+
});
139+
140+
it('does not apply fixed price promo when it is not cheaper than plan price', () => {
141+
const plan = createPlan({ monthlyCharge: 100 });
142+
const price = calculatePromoCodePlanPrice({
143+
type: 'fixed_price',
144+
amount: 100,
145+
} as any, plan);
146+
147+
expect(price).toMatchObject({
148+
isApplicable: false,
149+
finalAmount: 100,
150+
discountAmount: 0,
151+
});
152+
});
153+
125154
it('returns preview for percent discount promo', async () => {
126155
const plan = createPlan({ monthlyCharge: 1000 });
127156
const promoCode = createPromoCode({

0 commit comments

Comments
 (0)