온라인 쇼핑몰에서의 할인 전략, 쿠폰과 포인트의 최적 적용 순서
온라인 쇼핑몰에서 고객에게 제공되는 다양한 할인 혜택은 구매 결정에 큰 영향을 미칩니다. 특히, n% 할인 쿠폰과 m포인트 차감이 동시에 적용될 때, 어떤 할인을 먼저 적용하는지는 고객에게 제공되는 가치, 비즈니스 전략, 그리고 고객 경험 측면에서 중요한 고려 사항입니다.
이번 프로젝트에서 결제 기능을 작업하면서 위와 같은 고려사항을 기반으로 코드를 반영해보았습니다. 본 글에서는 이러한 할인의 적용 순서를 결정하는 기준과 그 근거에 대해 설명하고자 합니다.
결제할 때 할인 쿠폰 먼저인가 포인트 차감이 먼저인가
할인 적용의 기본 원칙
할인 적용 순서를 결정하기 위한 필자가 생각한 기본적인 원칙은 다음과 같습니다.
1. 할인 금액의 극대화
정률 할인은 구매 금액에 비례하여 할인 금액이 결정됩니다. 따라서, 전체 금액에서 먼저 정률 할인을 적용하면, 할인 받을 수 있는 기반이 되는 금액이 더 크기 때문에 더 많은 할인 금액을 얻을 수 있습니다. 반면, 포인트를 먼저 사용하면 할인을 적용할 금액이 줄어들어, 정률 할인의 효과가 감소합니다.
예시: 10000원에 10% 할인 쿠폰과 1000원 포인트 차감이 있을 경우,
할인 먼저: 10000원의 10%는 1000원 할인 → 남은 금액 9000원에서 1000원 포인트 차감 = 최종 8000원
포인트 먼저: 10000원에서 1000원 포인트 차감 → 남은 금액 9000원의 10%는 900원 할인 = 최종 8100원
2. 비즈니스 전략과의 일치성
많은 비즈니스에서 쿠폰은 고객 유치 및 매출 증대를 위한 마케팅 도구로 활용됩니다. 쿠폰 할인을 먼저 적용함으로써, 비즈니스는 쿠폰의 가치를 더욱 부각시킬 수 있으며, 이는 쿠폰을 통한 프로모션 효과를 극대화합니다. 즉, 고객이 더 큰 할인을 경험하게 함으로써, 쿠폰의 매력을 증가시키고 재방문 유도 및 고객 만족도를 높일 수 있습니다.
3. 투명한 고객 경험
고객 입장에서는 할인 과정이 명확하고 이해하기 쉬울 때 더 큰 만족감을 느낍니다. 정률 할인을 먼저 적용하는 방식은 고객이 쉽게 계산할 수 있으며, 얼마나 많은 할인을 받았는지 직관적으로 파악할 수 있게 합니다. 이는 고객이 자신이 받는 혜택을 명확하게 인식하고, 서비스에 대한 신뢰감을 높이는 데 기여합니다.
실제 적용 코드
결제 시스템에 적용된 할인 로직은 위의 원칙을 반영하여 설계되었습니다. 구체적인 코드 분석을 통해, 어떻게 할인이 적용되는지 살펴보겠습니다.
// 전체 할인 적용
private async applyDiscounts(
totalAmount: number,
userId: string,
couponId?: string,
pointAmountToUse?: number,
): Promise<number> {
const couponDiscount = couponId ? await this.applyCoupon(couponId, userId, totalAmount) : 0;
const pointDiscount = pointAmountToUse
? await this.applyPoints(pointAmountToUse, userId)
: 0;
// 최종 금액 계산
const finalAmount = totalAmount - (couponDiscount + pointDiscount);
return finalAmount < 0 ? 0 : finalAmount;
}
쿠폰 할인 적용
사용자가 보유한 쿠폰 ID와 사용자 ID를 기반으로, 해당 쿠폰의 유효성을 검사합니다. 쿠폰이 유효하다면, 쿠폰 유형(정률 또는 정액)에 따라 할인액을 계산합니다. 이 단계에서는 전체 구매 금액에서 먼저 할인이 적용됩니다.
private async applyCoupon(couponId: string, userId: string, totalAmount: number): Promise<number> {
const issuedCoupon = await this.issuedCouponRepository.findOne({
where: { coupon: { id: couponId }, user: { id: userId } },
});
if (!issuedCoupon) {
throw new BusinessException('payment', `user doesn't have coupon. couponId: ${couponId} userId: ${userId}`, 'Invalid coupon', HttpStatus.BAD_REQUEST);
}
const isValid = issuedCoupon?.isValid && issuedCoupon?.validFrom <= new Date() && issuedCoupon?.validUntil > new Date();
if (!isValid) {
throw new BusinessException('payment', `Invalid coupon type. couponId: ${couponId} userId: ${userId}`, 'Invalid coupon', HttpStatus.BAD_REQUEST);
}
const { coupon } = issuedCoupon;
if (coupon.type === 'percent') {
return (totalAmount * coupon.value) / 100;
} else if (coupon.type === 'fixed') {
return coupon.value;
}
return 0;
}
포인트 할인 적용
이어서, 사용자가 사용하기로 한 포인트 금액을 확인하고, 사용 가능한 포인트 범위 내에서 차감합니다. 포인트는 쿠폰 할인이 적용된 금액에 대해 추가로 할인을 제공합니다.
private async applyPoints(pointAmountToUse: number, userId: string): Promise<number> {
const point = await this.pointRepository.findOne({
where: { user: { id: userId } },
});
if (point.availableAmount < 0 || point.availableAmount < pointAmountToUse) {
throw new BusinessException('payment', `Invalid points amount ${point.availableAmount}`, 'Invalid points', HttpStatus.BAD_REQUEST);
}
return pointAmountToUse;
}
이 과정은 고객에게 최대한의 할인 혜택을 제공하고, 동시에 할인 적용 과정을 명확하고 이해하기 쉽게 만듭니다. 또한, 이러한 순서는 쿠폰을 통한 마케팅 전략을 효과적으로 지원하며, 고객 충성도를 높이는 데 기여할 수 있습니다.
끝으로
할인 적용 순서의 결정은 고객 가치, 비즈니스 전략, 그리고 고객 경험을 모두 고려하여 이루어져야 합니다. 본 사례에서 채택된 할인 순서는 이러한 원칙에 기반하여, 고객에게 가장 유리하며, 비즈니스 목표를 효과적으로 지원하고, 고객 경험을 향상시키는 방향으로 설계되었습니다. 할인 정책은 상황에 따라 다를 수 있으므로, 각기 다른 시나리오를 분석하고 비교하여 최적의 방법을 선택하는 것이 중요합니다.
▼ 프로젝트 진행간 작업 기록 ▼
'사이드 프로젝트 > 로그인 & 회원가입 & 결제' 카테고리의 다른 글
로그인 & 회원가입 & 결재 프로젝트 KPT (0) | 2024.03.29 |
---|---|
클라우드타입(Cloudtype)으로 프로젝트 무료 배포, 장점, 방법, DB 접속 (1) | 2024.03.24 |
프로젝트 작업 기록 - 예시 코드 clone, 동작 확인 (docker, DB 세팅) (0) | 2024.03.20 |
로그인, 회원가입, 결제 기능 프로젝트 기획, NestJS와 TypeORM 채택 (0) | 2024.03.18 |