修复仲裁退款并新增免押额度

This commit is contained in:
yml
2026-06-08 21:00:39 +08:00
parent 830cfcf33d
commit 0b419f5084
22 changed files with 559 additions and 72 deletions
+76 -16
View File
@@ -3,6 +3,7 @@ package dispute
import (
"encoding/json"
"errors"
"math"
"time"
"hfb_sys/backend/internal/auditlog"
@@ -17,13 +18,28 @@ import (
)
type Repository struct {
db *gorm.DB
db *gorm.DB
refundFunc RefundFunc
}
// RefundFunc 由 payment 模块注入,避免 dispute 与 payment 形成循环依赖。
type RefundFunc func(orderID uint64, refundAmountCent int64, bizType string, remark string) (status string, err error)
type refundAction struct {
OrderID uint64
RefundAmountCent int64
BizType string
Remark string
}
func NewRepository(db *gorm.DB) *Repository {
return &Repository{db: db}
}
func (r *Repository) SetRefundFunc(fn RefundFunc) {
r.refundFunc = fn
}
func (r *Repository) Create(userID uint64, orderID uint64, req CreateRequest) (*DisputeDTO, error) {
var createdID uint64
err := r.db.Transaction(func(tx *gorm.DB) error {
@@ -172,6 +188,7 @@ func (r *Repository) ListAdmin(page, pageSize int) (*PaginatedResult, error) {
}
func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest, meta AuditMeta) (*DisputeDTO, error) {
var refund *refundAction
err := r.db.Transaction(func(tx *gorm.DB) error {
var row model.Dispute
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&row, id).Error; err != nil {
@@ -197,7 +214,11 @@ func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest,
beforeSettlementStatus := order.SettlementStatus
beforeListingStatus := listing.Status
beforeAccountStatus := account.Status
settlement, err := buildArbitrationSettlement(order, req)
frozenBalance, err := renterFrozenBalance(tx, order.RenterID)
if err != nil {
return err
}
settlement, err := buildArbitrationSettlement(order, req, frozenBalance)
if err != nil {
return err
}
@@ -227,6 +248,14 @@ func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest,
if err := wallet.AppendEntries(tx, settlement.Entries...); err != nil {
return err
}
if settlement.RenterRefundAmount > 0 {
refundCent := int64(math.Round(settlement.RenterRefundAmount * 100))
action, err := r.prepareRefund(&order, refundCent, "arbitration_refund", "仲裁退款原路退还")
if err != nil {
return err
}
refund = action
}
if err := tx.Save(&row).Error; err != nil {
return err
}
@@ -288,6 +317,7 @@ func (r *Repository) Arbitrate(adminID uint64, id uint64, req ArbitrateRequest,
if err != nil {
return nil, err
}
r.startRefundBestEffort(refund)
var row disputeRow
if err := r.baseQuery().Where("d.id = ?", id).First(&row).Error; err != nil {
return nil, err
@@ -303,7 +333,7 @@ type arbitrationSettlement struct {
DepositDeductAmount float64
}
func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest) (arbitrationSettlement, error) {
func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest, renterFrozenBalance float64) (arbitrationSettlement, error) {
total := roundMoney(order.RentAmount + order.DepositAmount)
ownerRentAmount := roundMoney(order.OwnerRentAmount)
if ownerRentAmount <= 0 || ownerRentAmount > order.RentAmount {
@@ -311,16 +341,17 @@ func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest) (
}
settlement := arbitrationSettlement{}
orderID := order.ID
if total > 0 {
releaseFrozenAmount := minMoney(total, roundMoney(renterFrozenBalance))
if releaseFrozenAmount > 0 {
settlement.Entries = append(settlement.Entries, wallet.Entry{
UserID: order.RenterID,
OrderID: &orderID,
Direction: "out",
Amount: total,
Amount: releaseFrozenAmount,
BalanceType: "frozen",
BizType: "arbitration_release_frozen",
BizNo: order.OrderNo,
Remark: "仲裁释放开发态模拟冻结金额",
Remark: "仲裁释放冻结金额",
})
}
@@ -329,16 +360,6 @@ func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest) (
return
}
settlement.RenterRefundAmount += amount
settlement.Entries = append(settlement.Entries, wallet.Entry{
UserID: order.RenterID,
OrderID: &orderID,
Direction: "in",
Amount: amount,
BalanceType: "available",
BizType: "arbitration_renter_refund",
BizNo: order.OrderNo,
Remark: remark,
})
}
addOwnerIncome := func(amount float64, remark string) {
if amount <= 0 {
@@ -391,6 +412,45 @@ func buildArbitrationSettlement(order model.RentalOrder, req ArbitrateRequest) (
return settlement, nil
}
func (r *Repository) prepareRefund(order *model.RentalOrder, amountCent int64, bizType string, remark string) (*refundAction, error) {
if amountCent <= 0 {
return nil, nil
}
if r.refundFunc == nil {
return nil, ErrDependencyUnavailable
}
order.RefundStatus = "pending"
order.RefundAmountCent = amountCent
order.RefundedAt = nil
return &refundAction{
OrderID: order.ID,
RefundAmountCent: amountCent,
BizType: bizType,
Remark: remark,
}, nil
}
func (r *Repository) startRefundBestEffort(action *refundAction) {
if action == nil || r.refundFunc == nil {
return
}
_, _ = r.refundFunc(action.OrderID, action.RefundAmountCent, action.BizType, action.Remark)
}
func renterFrozenBalance(tx *gorm.DB, renterID uint64) (float64, error) {
var account model.WalletAccount
err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
Where("user_id = ?", renterID).
First(&account).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return 0, nil
}
if err != nil {
return 0, err
}
return account.FrozenBalance, nil
}
// minMoney 返回较小金额(角精度)
func minMoney(a float64, b float64) float64 {
return money.Min(a, b)