fix(distribution): 修复分销结账退款分成计算逻辑与利润统计,优化分销订单表格列宽与展示体验

This commit is contained in:
yml2213
2026-09-09 19:34:04 +08:00
parent 19b18324a2
commit b16c45ce6f
12 changed files with 403 additions and 88 deletions
@@ -240,7 +240,7 @@ func SnapshotPaidOrderTx(tx *gorm.DB, orderID uint64, grossPaidCent int64) error
return tx.Create(&parties).Error
}
// ApplyRefundTx 按累计成功退款金额重算手续费、分成基数和各方分成,不覆盖订单创建时的规则版本。
// ApplyRefundTx 按累计成功退款或结账结算重算手续费、分成基数和各方分成,不覆盖订单创建时的规则版本。
func ApplyRefundTx(tx *gorm.DB, orderID uint64, refundAmountCent int64) error {
if !distributionTablesPresent(tx) {
return nil
@@ -255,33 +255,96 @@ func ApplyRefundTx(tx *gorm.DB, orderID uint64, refundAmountCent int64) error {
if refundAmountCent < 0 {
return ErrInvalidAmount
}
if refundAmountCent > financial.GrossPaidAmountCent {
refundAmountCent = financial.GrossPaidAmountCent
}
var rule model.DistributionRuleVersion
if err := tx.First(&rule, financial.RuleVersionID).Error; err != nil {
return err
}
var order model.RentalOrder
ownerRent := int64(0)
if err := tx.Select("owner_rent_amount_cent").First(&order, orderID).Error; err == nil {
ownerRent = order.OwnerRentAmountCent
if err := tx.First(&order, orderID).Error; err != nil {
return err
}
// 判定实际租金退款和号主应得租金:
// 1. 如果存在已达成一致的结账单(accepted 或 settled),以结账单中的实际消费租金与号主实际所得为准
var checkout model.OrderCheckout
hasAcceptedCheckout := false
if err := tx.Where("order_id = ? AND status IN ('accepted', 'settled')", orderID).
Order("id DESC").First(&checkout).Error; err == nil {
hasAcceptedCheckout = true
}
rentRefundCent := refundAmountCent
ownerRent := order.OwnerRentAmountCent
if ownerRent < 0 {
ownerRent = 0
}
if hasAcceptedCheckout {
// 结账单中,实际有效租金为 checkout.RentAmountCent
// 真实的租金退款为 订单初始租金 - 实际有效租金
actualRentRefund := order.RentAmountCent - checkout.RentAmountCent
if actualRentRefund < 0 {
actualRentRefund = 0
}
rentRefundCent = actualRentRefund
// 号主实际租金所得以结账单的实际租金收入为准
ownerRent = checkout.OwnerRentAmountCent
if ownerRent < 0 {
ownerRent = 0
}
} else {
// 无结账单场景(例如交接超时、提前取消退款、维权全额退款):
// refundAmountCent 是租客收到的总退款(含押金与租金),押金不计入分销毛收入
// 先抵扣押金退款,剩余部分才属于租金退款
depositRefund := order.DepositAmountCent
if refundAmountCent < depositRefund {
depositRefund = refundAmountCent
}
actualRentRefund := refundAmountCent - depositRefund
if actualRentRefund < 0 {
actualRentRefund = 0
}
rentRefundCent = actualRentRefund
// 如果租金全额退款,号主应得租金为 0
if rentRefundCent >= financial.GrossPaidAmountCent {
ownerRent = 0
}
}
result, err := calculateForRule(rule, SettlementInput{GrossPaidAmountCent: financial.GrossPaidAmountCent, RefundAmountCent: refundAmountCent, OwnerRentAmountCent: ownerRent, MarkupAmountCent: financial.MarkupAmountCent})
if rentRefundCent > financial.GrossPaidAmountCent {
rentRefundCent = financial.GrossPaidAmountCent
}
result, err := calculateForRule(rule, SettlementInput{
GrossPaidAmountCent: financial.GrossPaidAmountCent,
RefundAmountCent: rentRefundCent,
OwnerRentAmountCent: ownerRent,
MarkupAmountCent: financial.MarkupAmountCent,
})
if err != nil {
return err
}
splits := SplitSettlement(ruleFromVersion(rule), result.SplitBaseAmountCent, financial.MarkupAmountCent)
if err := tx.Model(&financial).Updates(map[string]any{"refund_amount_cent": refundAmountCent, "net_paid_amount_cent": result.NetPaidAmountCent, "payment_fee_cent": result.PaymentFeeCent, "service_fee_cent": result.ServiceFeeCent, "split_base_amount_cent": result.SplitBaseAmountCent, "rounding_adjustment_cent": SplitRoundingCent(result.SplitBaseAmountCent, result.ServiceFeeCent, financial.MarkupAmountCent, splits), "settlement_status": "pending"}).Error; err != nil {
if err := tx.Model(&financial).Updates(map[string]any{
"refund_amount_cent": rentRefundCent,
"net_paid_amount_cent": result.NetPaidAmountCent,
"payment_fee_cent": result.PaymentFeeCent,
"service_fee_cent": result.ServiceFeeCent,
"split_base_amount_cent": result.SplitBaseAmountCent,
"rounding_adjustment_cent": SplitRoundingCent(result.SplitBaseAmountCent, result.ServiceFeeCent, financial.MarkupAmountCent, splits),
"settlement_status": "pending",
}).Error; err != nil {
return err
}
for _, split := range splits {
if err := tx.Model(&model.DistributionOrderParty{}).
Where("order_id = ? AND party_role = ?", orderID, split.PartyRole).
Updates(map[string]any{"income_amount_cent": split.AmountCent, "profit_amount_cent": split.AmountCent}).Error; err != nil {
Updates(map[string]any{
"income_amount_cent": split.AmountCent,
"profit_amount_cent": split.AmountCent,
}).Error; err != nil {
return err
}
}