修复仲裁退款并新增免押额度
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user