按实际纯币金额计算租客优惠与积分

This commit is contained in:
yml2213
2026-07-27 10:45:41 +08:00
parent 99e8eb28af
commit 8af7333969
30 changed files with 983 additions and 154 deletions
+96 -15
View File
@@ -26,6 +26,7 @@ const (
MaxLevelPoints = 1_000_000_000
MaxLevelQuotaCent = 100_000_000
SourceOrderCompleted = "order_completed"
SourceOrderRefunded = "order_refunded"
SourceAdminAdjustment = "admin_adjustment"
)
@@ -243,7 +244,7 @@ func CalculateDiscountCent(originalRentCent int64, platformFeeCent int64, discou
return discountCent
}
func AwardOrderCompleted(tx *gorm.DB, order *model.RentalOrder, actualRentCent int64, source string) error {
func AwardOrderCompleted(tx *gorm.DB, order *model.RentalOrder, actualPureCoinCent int64, source string) error {
if tx == nil || order == nil || order.ID == 0 || order.RenterID == 0 {
return nil
}
@@ -271,10 +272,12 @@ func AwardOrderCompleted(tx *gorm.DB, order *model.RentalOrder, actualRentCent i
if err != nil {
return err
}
order.GrowthPointsBasisCent = maxInt64(actualPureCoinCent, 0)
order.GrowthPointsPerYuan = cfg.PointsPerYuan
if !cfg.Enabled {
return nil
}
points := PointsForRent(actualRentCent, cfg.PointsPerYuan)
points := PointsForPureCoin(actualPureCoinCent, cfg.PointsPerYuan)
if points <= 0 {
return nil
}
@@ -293,16 +296,18 @@ func AwardOrderCompleted(tx *gorm.DB, order *model.RentalOrder, actualRentCent i
}
now := time.Now()
ledger := model.RenterGrowthLedger{
UserID: order.RenterID,
OrderID: &order.ID,
Points: points,
BeforePoints: beforePoints,
AfterPoints: afterPoints,
BeforeLevel: beforeLevel.Code,
AfterLevel: afterLevel.Code,
Source: source,
Remark: "租号订单完成发放成长积分",
CreatedAt: now,
UserID: order.RenterID,
OrderID: &order.ID,
Points: points,
BasisAmountCent: actualPureCoinCent,
PointsPerYuan: cfg.PointsPerYuan,
BeforePoints: beforePoints,
AfterPoints: afterPoints,
BeforeLevel: beforeLevel.Code,
AfterLevel: afterLevel.Code,
Source: source,
Remark: "租号订单完成发放成长积分",
CreatedAt: now,
}
if err := tx.Create(&ledger).Error; err != nil {
return err
@@ -312,14 +317,90 @@ func AwardOrderCompleted(tx *gorm.DB, order *model.RentalOrder, actualRentCent i
return nil
}
func PointsForRent(actualRentCent int64, pointsPerYuan int64) int64 {
if actualRentCent <= 0 {
// RevokeOrderCompleted 在已完成订单被全额人工退款后扣回该单已发放的成长积分。
func RevokeOrderCompleted(tx *gorm.DB, order *model.RentalOrder) error {
if tx == nil || order == nil || order.ID == 0 || order.RenterID == 0 {
return nil
}
var existing model.RenterGrowthLedger
err := tx.Where("order_id = ? AND source = ?", order.ID, SourceOrderRefunded).First(&existing).Error
if err == nil {
return nil
}
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
points := order.GrowthPointsAwarded
if points <= 0 {
var awarded model.RenterGrowthLedger
if err := tx.Where("order_id = ? AND source = ?", order.ID, SourceOrderCompleted).First(&awarded).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
points = awarded.Points
}
if points <= 0 {
return nil
}
cfg, err := ConfigForTx(tx)
if err != nil {
return err
}
var user model.User
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&user, order.RenterID).Error; err != nil {
return err
}
beforePoints := maxInt64(user.RenterGrowthPoints, 0)
revokedPoints := points
if revokedPoints > beforePoints {
revokedPoints = beforePoints
}
beforeLevel := LevelForPoints(cfg, beforePoints)
afterPoints := beforePoints - revokedPoints
afterLevel := LevelForPoints(cfg, afterPoints)
if !cfg.Enabled {
beforeLevel = LevelRule{Code: DefaultLevelCode, Name: DefaultLevelName}
afterLevel = beforeLevel
}
user.RenterGrowthPoints = afterPoints
user.RenterGrowthLevel = afterLevel.Code
if err := tx.Save(&user).Error; err != nil {
return err
}
orderID := order.ID
return tx.Create(&model.RenterGrowthLedger{
UserID: order.RenterID,
OrderID: &orderID,
Points: -revokedPoints,
BasisAmountCent: order.GrowthPointsBasisCent,
PointsPerYuan: order.GrowthPointsPerYuan,
BeforePoints: beforePoints,
AfterPoints: afterPoints,
BeforeLevel: beforeLevel.Code,
AfterLevel: afterLevel.Code,
Source: SourceOrderRefunded,
Remark: "已完成订单全额退款扣回成长积分",
CreatedAt: time.Now(),
}).Error
}
func PointsForPureCoin(actualPureCoinCent int64, pointsPerYuan int64) int64 {
if actualPureCoinCent <= 0 {
return 0
}
if pointsPerYuan <= 0 {
pointsPerYuan = DefaultPointsPerYuan
}
return (actualRentCent / 100) * pointsPerYuan
return (actualPureCoinCent / 100) * pointsPerYuan
}
// PointsForRent 保留旧调用兼容,积分基数现统一解释为实际纯币金额。
func PointsForRent(actualPureCoinCent int64, pointsPerYuan int64) int64 {
return PointsForPureCoin(actualPureCoinCent, pointsPerYuan)
}
func LevelForPoints(cfg Config, points int64) LevelRule {