Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
@@ -58,3 +58,26 @@ func calculatePurchasePrice(
|
|||||||
result.DiscountAmount = originalPrice - result.PayableBase
|
result.DiscountAmount = originalPrice - result.PayableBase
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateRenewalPrice(
|
||||||
|
ctx context.Context,
|
||||||
|
svcCtx *svc.ServiceContext,
|
||||||
|
userID int64,
|
||||||
|
subscribeID int64,
|
||||||
|
unitPrice int64,
|
||||||
|
quantity int64,
|
||||||
|
discounts []types.SubscribeDiscount,
|
||||||
|
eligibleForDiscount bool,
|
||||||
|
) (*orderPriceResult, error) {
|
||||||
|
return calculatePurchasePrice(
|
||||||
|
ctx,
|
||||||
|
svcCtx,
|
||||||
|
userID,
|
||||||
|
subscribeID,
|
||||||
|
unitPrice,
|
||||||
|
quantity,
|
||||||
|
discounts,
|
||||||
|
eligibleForDiscount,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -297,3 +297,78 @@ func TestCalculatePurchasePriceNewUserGatedByFirstPurchase(t *testing.T) {
|
|||||||
t.Fatalf("PayableBase = %d, want 900 (regular 90%% discount)", result.PayableBase)
|
t.Fatalf("PayableBase = %d, want 900 (regular 90%% discount)", result.PayableBase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCalculateRenewalPriceCampaignAppliesToReturningUsers(t *testing.T) {
|
||||||
|
model := &fakePromoModel{rules: []*promo.RuleWithPrice{
|
||||||
|
{
|
||||||
|
Rule: promo.Rule{
|
||||||
|
Id: 21,
|
||||||
|
Name: "renewal campaign",
|
||||||
|
Type: promo.RuleTypeCampaign,
|
||||||
|
Enabled: true,
|
||||||
|
},
|
||||||
|
PromoPrice: 700,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
svcCtx := &svc.ServiceContext{DB: &gorm.DB{}, PromoModel: model}
|
||||||
|
|
||||||
|
result, err := calculateRenewalPrice(
|
||||||
|
context.Background(),
|
||||||
|
svcCtx,
|
||||||
|
42,
|
||||||
|
2,
|
||||||
|
500,
|
||||||
|
3,
|
||||||
|
[]types.SubscribeDiscount{{Quantity: 3, Discount: 80}},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("calculateRenewalPrice returned error: %v", err)
|
||||||
|
}
|
||||||
|
if result.OriginalPrice != 1500 {
|
||||||
|
t.Fatalf("OriginalPrice = %d, want 1500", result.OriginalPrice)
|
||||||
|
}
|
||||||
|
if result.PayableBase != 700 {
|
||||||
|
t.Fatalf("PayableBase = %d, want 700", result.PayableBase)
|
||||||
|
}
|
||||||
|
if result.DiscountAmount != 0 {
|
||||||
|
t.Fatalf("DiscountAmount = %d, want 0 when promo applies", result.DiscountAmount)
|
||||||
|
}
|
||||||
|
if result.PromoRuleId != 21 {
|
||||||
|
t.Fatalf("PromoRuleId = %d, want 21", result.PromoRuleId)
|
||||||
|
}
|
||||||
|
if result.PromoDiscount != 800 {
|
||||||
|
t.Fatalf("PromoDiscount = %d, want 800", result.PromoDiscount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCalculateRenewalPriceFallsBackToRegularDiscountWhenPromoMisses(t *testing.T) {
|
||||||
|
model := &fakePromoModel{rules: nil}
|
||||||
|
svcCtx := &svc.ServiceContext{DB: &gorm.DB{}, PromoModel: model}
|
||||||
|
|
||||||
|
result, err := calculateRenewalPrice(
|
||||||
|
context.Background(),
|
||||||
|
svcCtx,
|
||||||
|
42,
|
||||||
|
2,
|
||||||
|
500,
|
||||||
|
3,
|
||||||
|
[]types.SubscribeDiscount{{Quantity: 3, Discount: 80}},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("calculateRenewalPrice returned error: %v", err)
|
||||||
|
}
|
||||||
|
if result.OriginalPrice != 1500 {
|
||||||
|
t.Fatalf("OriginalPrice = %d, want 1500", result.OriginalPrice)
|
||||||
|
}
|
||||||
|
if result.PayableBase != 1200 {
|
||||||
|
t.Fatalf("PayableBase = %d, want 1200", result.PayableBase)
|
||||||
|
}
|
||||||
|
if result.DiscountAmount != 300 {
|
||||||
|
t.Fatalf("DiscountAmount = %d, want 300", result.DiscountAmount)
|
||||||
|
}
|
||||||
|
if result.PromoRuleId != 0 || result.PromoDiscount != 0 {
|
||||||
|
t.Fatalf("promo fields = (%d, %d), want (0, 0)", result.PromoRuleId, result.PromoDiscount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package order
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@@ -165,13 +164,28 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene
|
|||||||
)
|
)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var discount float64 = 1
|
priceResult, err := calculateRenewalPrice(
|
||||||
if len(newUserDiscount.Discounts) > 0 {
|
l.ctx,
|
||||||
discount = getDiscount(newUserDiscount.Discounts, req.Quantity, newUserDiscount.EligibleForDiscount)
|
l.svcCtx,
|
||||||
|
entitlement.EffectiveUserID,
|
||||||
|
userSubscribe.SubscribeId,
|
||||||
|
sub.UnitPrice,
|
||||||
|
req.Quantity,
|
||||||
|
newUserDiscount.Discounts,
|
||||||
|
newUserDiscount.EligibleForDiscount,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
l.Errorw("[Renewal] Promo price calculation error",
|
||||||
|
logger.Field("error", err.Error()),
|
||||||
|
logger.Field("user_id", u.Id),
|
||||||
|
logger.Field("effective_user_id", entitlement.EffectiveUserID),
|
||||||
|
logger.Field("subscribe_id", userSubscribe.SubscribeId),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
price := sub.UnitPrice * req.Quantity
|
price := priceResult.OriginalPrice
|
||||||
amount := int64(math.Round(float64(price) * discount))
|
amount := priceResult.PayableBase
|
||||||
discountAmount := price - amount
|
discountAmount := priceResult.DiscountAmount
|
||||||
|
|
||||||
// Validate amount to prevent overflow
|
// Validate amount to prevent overflow
|
||||||
if amount > MaxOrderAmount {
|
if amount > MaxOrderAmount {
|
||||||
@@ -269,6 +283,8 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene
|
|||||||
Amount: amount,
|
Amount: amount,
|
||||||
GiftAmount: deductionAmount,
|
GiftAmount: deductionAmount,
|
||||||
Discount: discountAmount,
|
Discount: discountAmount,
|
||||||
|
PromoRuleId: priceResult.PromoRuleId,
|
||||||
|
PromoDiscount: priceResult.PromoDiscount,
|
||||||
Coupon: req.Coupon,
|
Coupon: req.Coupon,
|
||||||
CouponDiscount: coupon,
|
CouponDiscount: coupon,
|
||||||
PaymentId: payment.Id,
|
PaymentId: payment.Id,
|
||||||
|
|||||||
Reference in New Issue
Block a user