统一处理百分比和系数两种折扣输入方式,增加边界保护 在金额计算中使用math.Round进行四舍五入处理 添加相关单元测试确保计算准确性
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"github.com/perfect-panel/server/internal/model/coupon"
|
||||
"math"
|
||||
"github.com/perfect-panel/server/internal/model/coupon"
|
||||
)
|
||||
|
||||
func calculateCoupon(amount int64, couponInfo *coupon.Coupon) int64 {
|
||||
if couponInfo.Type == 1 {
|
||||
return int64(float64(amount) * (float64(couponInfo.Discount) / float64(100)))
|
||||
} else {
|
||||
return min(couponInfo.Discount, amount)
|
||||
}
|
||||
if couponInfo.Type == 1 {
|
||||
return int64(math.Round(float64(amount) * (float64(couponInfo.Discount) / float64(100))))
|
||||
} else {
|
||||
return min(couponInfo.Discount, amount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package order
|
||||
|
||||
import "github.com/perfect-panel/server/internal/model/payment"
|
||||
import (
|
||||
"math"
|
||||
"github.com/perfect-panel/server/internal/model/payment"
|
||||
)
|
||||
|
||||
func calculateFee(amount int64, config *payment.Payment) int64 {
|
||||
var fee float64
|
||||
@@ -16,5 +19,5 @@ func calculateFee(amount int64, config *payment.Payment) int64 {
|
||||
case 3:
|
||||
fee = float64(amount)*(float64(config.FeePercent)/float64(100)) + float64(config.FeeAmount)
|
||||
}
|
||||
return int64(fee)
|
||||
return int64(math.Round(fee))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/perfect-panel/server/internal/model/coupon"
|
||||
)
|
||||
|
||||
func TestCalculateCoupon_Percent(t *testing.T) {
|
||||
c := &coupon.Coupon{Type: 1, Discount: 10}
|
||||
got := calculateCoupon(1000, c)
|
||||
if got != 100 {
|
||||
t.Fatalf("percent coupon expected 100, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateCoupon_PercentRounding(t *testing.T) {
|
||||
c := &coupon.Coupon{Type: 1, Discount: 10}
|
||||
got := calculateCoupon(999, c) // 999*10% = 99.9 → round to 100
|
||||
if got != 100 {
|
||||
t.Fatalf("percent coupon rounding expected 100, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateCoupon_FixedCap(t *testing.T) {
|
||||
c := &coupon.Coupon{Type: 2, Discount: 300}
|
||||
got := calculateCoupon(200, c)
|
||||
if got != 200 {
|
||||
t.Fatalf("fixed coupon capped by amount expected 200, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/perfect-panel/server/internal/model/payment"
|
||||
)
|
||||
|
||||
func TestCalculateFee_Percent(t *testing.T) {
|
||||
p := &payment.Payment{FeeMode: 1, FeePercent: 5}
|
||||
if calculateFee(1000, p) != 50 {
|
||||
t.Fatal("fee percent 5% of 1000 should be 50")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateFee_PercentRounding(t *testing.T) {
|
||||
p := &payment.Payment{FeeMode: 1, FeePercent: 5}
|
||||
if calculateFee(999, p) != 50 { // 999*5% = 49.95 → round to 50
|
||||
t.Fatal("fee percent 5% of 999 should round to 50")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateFee_Fixed(t *testing.T) {
|
||||
p := &payment.Payment{FeeMode: 2, FeeAmount: 300}
|
||||
if calculateFee(1000, p) != 300 {
|
||||
t.Fatal("fixed fee 300 should be 300")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateFee_Mixed(t *testing.T) {
|
||||
p := &payment.Payment{FeeMode: 3, FeePercent: 10, FeeAmount: 100}
|
||||
if calculateFee(1000, p) != 200 {
|
||||
t.Fatal("mixed fee 10% + 100 of 1000 should be 200")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,20 @@ import "github.com/perfect-panel/server/internal/types"
|
||||
// 参数:discounts 折扣规则列表(数量阈值 + 折扣倍数);inputMonths 购买时长
|
||||
// 返回:最终价格倍数(如 0.95 表示按 95% 计价)
|
||||
func getDiscount(discounts []types.SubscribeDiscount, inputMonths int64) float64 {
|
||||
var finalDiscount float64 = 1.0
|
||||
var finalDiscount float64 = 1.0
|
||||
|
||||
for _, discount := range discounts {
|
||||
if inputMonths >= discount.Quantity && discount.Discount < finalDiscount {
|
||||
finalDiscount = discount.Discount
|
||||
}
|
||||
}
|
||||
for _, d := range discounts {
|
||||
val := d.Discount
|
||||
if val > 1 && val <= 100 {
|
||||
val = val / 100.0
|
||||
}
|
||||
if val < 0 {
|
||||
val = 0
|
||||
}
|
||||
if inputMonths >= d.Quantity && val < finalDiscount {
|
||||
finalDiscount = val
|
||||
}
|
||||
}
|
||||
|
||||
return finalDiscount
|
||||
return finalDiscount
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package order
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
)
|
||||
|
||||
func TestGetDiscount_Coefficient(t *testing.T) {
|
||||
discounts := []types.SubscribeDiscount{{Quantity: 7, Discount: 0.95}}
|
||||
got := getDiscount(discounts, 7)
|
||||
if got != 0.95 {
|
||||
t.Fatalf("expected 0.95, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDiscount_Percentage(t *testing.T) {
|
||||
discounts := []types.SubscribeDiscount{{Quantity: 7, Discount: 95}}
|
||||
got := getDiscount(discounts, 7)
|
||||
if got != 0.95 {
|
||||
t.Fatalf("expected 0.95 from 95%%, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDiscount_InvalidOver100(t *testing.T) {
|
||||
discounts := []types.SubscribeDiscount{{Quantity: 7, Discount: 120}}
|
||||
got := getDiscount(discounts, 7)
|
||||
if got != 1.0 {
|
||||
t.Fatalf("expected 1.0 when invalid >100, got %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package order
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math"
|
||||
|
||||
"github.com/perfect-panel/server/internal/model/order"
|
||||
"github.com/perfect-panel/server/pkg/tool"
|
||||
@@ -63,7 +64,7 @@ func (l *PreCreateOrderLogic) PreCreateOrder(req *types.PurchaseOrderRequest) (r
|
||||
}
|
||||
price := sub.UnitPrice * req.Quantity
|
||||
|
||||
amount := int64(float64(price) * discount)
|
||||
amount := int64(math.Round(float64(price) * discount))
|
||||
discountAmount := price - amount
|
||||
var couponAmount int64
|
||||
if req.Coupon != "" {
|
||||
|
||||
@@ -3,6 +3,7 @@ package order
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/perfect-panel/server/internal/model/log"
|
||||
@@ -102,7 +103,7 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P
|
||||
}
|
||||
price := sub.UnitPrice * req.Quantity
|
||||
// discount amount
|
||||
amount := int64(float64(price) * discount)
|
||||
amount := int64(math.Round(float64(price) * discount))
|
||||
discountAmount := price - amount
|
||||
var coupon int64 = 0
|
||||
// Calculate the coupon deduction
|
||||
|
||||
Reference in New Issue
Block a user