문제 상황
현재 프로젝트에서 사용자가 보유한 쿠폰을 불러와 결제 시 적용할 수 있는 기능을 개발하던 중, 선택된 쿠폰의 할인률에 따라 결제 금액에서 할인을 계산하는 로직을 구현하고 있었습니다.
위와 같이 사용자가 10% 할인 쿠폰을 선택하여 결제 금액이 20,000원일 때, 기대한 할인액은 2,000원이지만, 실제로는 50원만 할인되는 문제가 발생했습니다.
쿠폰 데이터는 다음과 같은 정보가 포함되어 있었습니다.
쿠폰 데이터
Coupon: CouponUserResponseDto(
couponId=b2e6f1b4-1234-4cb5-8234-8a9e6b78c2c2,
promotionId=a1e6f1b4-9187-4cb5-8225-8a9e6b78c2b1,
description=10% Discount Coupon,
discountType=PERCENTAGE,
discountValue=10.00,
maxDiscount=50.00,
validFrom=2024-10-18,
validUntil=2024-12-31,
status=ACTIVE,
isUsed=false
)
위 로그에서 discountValue=10.00(할인율)을 통해 할인율이 10%로 설정되었음에도 불구하고, 계산된 할인액이 2,000원이 아닌 50원이 적용되고 있는 것을 확인했습니다.
문제의 코드
할인 계산을 수행하는 JavaScript 코드 일부는 다음과 같습니다.
couponSelect.addEventListener('change', function() {
var selectedCoupon = couponSelect.options[couponSelect.selectedIndex];
var originalAmount = parseInt(originalAmountSpan.textContent);
var discountAmount = 0;
if (selectedCoupon.value !== "") {
var couponData = JSON.parse(selectedCoupon.getAttribute('data-coupon'));
if (couponData.discountType === 'PERCENTAGE') {
discountAmount = Math.min(originalAmount * (couponData.discountValue / 100.0), couponData.maxDiscount);
} else {
discountAmount = Math.min(couponData.discountValue, originalAmount);
}
discountGroup.style.display = 'block';
finalAmountGroup.style.display = 'block';
} else {
discountGroup.style.display = 'none';
finalAmountGroup.style.display = 'none';
}
var finalAmount = originalAmount - discountAmount;
discountAmountSpan.textContent = discountAmount;
finalAmountSpan.textContent = finalAmount;
});
문제 원인
if (couponData.discountType === 'PERCENTAGE') {
discountAmount = Math.min(Math.round(originalAmount * (couponData.discountValue / 100.0)), couponData.maxDiscount);
} else {
discountAmount = Math.min(couponData.discountValue, originalAmount);
}
할인액이 지나치게 높아져 최종 결제 금액이 0원에 가까워지는 경우를 방지하기 위해, 최대 할인 한도인 maxDiscount를 설정했습니다.
현재 이 쿠폰의 maxDiscount 값이 50.00으로 지정되어 있어, 계산된 할인 금액이 2,000원이지만, 이 최대 할인 한도에 의해 50원으로 제한되고 있는 상황입니다.
문제 해결
할인 계산 로직에서 발생한 오류를 수정하기 위해, 쿠폰의 할인 유형이 'PERCENTAGE'일 경우 할인액을 올바르게 계산하도록 개선하였습니다.
우선, 할인액을 계산하기 위해 원래 금액에 할인율을 곱하는 방식은 유지하되, maxDiscount 값도 할인율로 해석하여 올바른 비율로 적용해야 한다는 점을 인식했습니다.
이 과정에서 할인액과 최대 할인액을 비교하여 적용할 금액을 결정하기 위해 다음과 같은 코드를 구현하였습니다.
if (couponData.discountType === 'PERCENTAGE') {
let calculatedDiscount = Math.round(originalAmount * (couponData.discountValue / 100.0));
let maxDiscountAmount = Math.round(originalAmount * (couponData.maxDiscount / 100.0));
discountAmount = Math.min(calculatedDiscount, maxDiscountAmount);
} else {
discountAmount = Math.min(couponData.discountValue, originalAmount);
}
1. 할인액 계산
- originalAmount에 couponData.discountValue를 백분율로 변환한 값(즉, 10%는 0.1로 변환)을 곱하여 할인액을 계산합니다. 이때 Math.round()를 사용하여 소수점을 반올림합니다.
2. 최대 할인액 계산
- maxDiscount도 원래 금액에 비율로 적용하여 최대 할인 한도를 재계산합니다.
- 이 과정에서도 소수점 처리를 위해 Math.round()를 활용합니다.
3. 최종 할인액 결정
- Math.min()을 통해 계산된 할인액과 최대 할인액 중 작은 값을 선택하여 실제 적용할 할인액을 결정합니다.
이렇게 수정된 로직을 통해, 최대 할인 제한이 실제 금액의 비율로 올바르게 반영되어 50원이 아닌 원래 가격의 50%로 계산됩니다.
결과적으로, 할인율의 소수 변환 과정에서 발생했던 문제를 해결함으로써, 예상했던 할인액이 정상적으로 적용될 수 있게 되었습니다.
즉, 나누기 100을 통해 퍼센트를 백분율로 변환해서 문제를 해결한 것입니다.
문제 해결 결과
위와 같이 할인율의 소수 변환 과정에서 발생했던 문제를 해결함으로써 예상했던 할인액이 정상적으로 적용된 것을 확인할 수 있습니다.
'Trouble Shooting' 카테고리의 다른 글
[트러블 슈팅] 사용자 직접 취소 시 다중 결과 반환 트러블 슈팅 (0) | 2024.10.11 |
---|---|
[트러블 슈팅] BeanCreationException 빈 충돌 해결을 위한 @ConditionalOnProperty 활용 (0) | 2024.10.11 |
[트러블 슈팅] 사용자 직접 결제 취소 시 서버 리다이렉트 문제 해결기 (0) | 2024.10.10 |
[트러블 슈팅] 토스페이먼츠 결제 트러블 슈팅 (0) | 2024.10.09 |
[트러블 슈팅] @ModelAttribute의 자동 변환 에러 해결 (0) | 2024.10.07 |