添加订单押金暂扣与归还
This commit is contained in:
@@ -29,6 +29,12 @@ type RentalOrder struct {
|
||||
RefundStatus string `gorm:"size:32;not null;default:'none';index" json:"refund_status"`
|
||||
RefundAmountCent int64 `gorm:"not null;default:0" json:"refund_amount_cent"`
|
||||
RefundedAt *time.Time `json:"refunded_at"`
|
||||
DepositHoldStatus string `gorm:"size:16;not null;default:'none';index" json:"deposit_hold_status"`
|
||||
DepositHoldAmountCent int64 `gorm:"not null;default:0" json:"deposit_hold_amount_cent"`
|
||||
DepositHoldReason string `gorm:"size:255;not null;default:''" json:"deposit_hold_reason"`
|
||||
DepositHeldBy *uint64 `json:"deposit_held_by"`
|
||||
DepositHeldAt *time.Time `json:"deposit_held_at"`
|
||||
DepositHoldReleasedAt *time.Time `json:"deposit_hold_released_at"`
|
||||
OwnerSettledAt *time.Time `json:"owner_settled_at"`
|
||||
SettledAt *time.Time `json:"settled_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -38,3 +44,45 @@ type RentalOrder struct {
|
||||
func (RentalOrder) TableName() string {
|
||||
return "rental_orders"
|
||||
}
|
||||
|
||||
// 押金暂扣状态:客服可对进行中订单的押金退款进行暂扣,订单照常结算,
|
||||
// 但本应原路退给租客的押金部分挂起不退,后续由客服手动归还。
|
||||
const (
|
||||
DepositHoldStatusNone = "none" // 未暂扣
|
||||
DepositHoldStatusHeld = "held" // 已暂扣(押金退款被拦截/挂起)
|
||||
DepositHoldStatusReleased = "released" // 已归还
|
||||
)
|
||||
|
||||
// IsDepositHeld 判断订单当前是否处于押金暂扣状态。
|
||||
func (o *RentalOrder) IsDepositHeld() bool {
|
||||
return o.DepositHoldStatus == DepositHoldStatusHeld
|
||||
}
|
||||
|
||||
// ApplyDepositHold 在任一结算退款路径中拦截押金退款。
|
||||
// totalRefundCent 是本次本应原路退还给租客的总金额(含租金退款和押金退款),
|
||||
// depositPortionCent 是其中属于押金退款的部分。
|
||||
// 若订单已暂扣,则把押金部分(不超过本次退款总额)从退款中扣除,
|
||||
// 并把尚未记录过的部分累加到暂扣金额(累计不超过实付押金),返回扣除后实际发起原路退款的金额;
|
||||
// 未暂扣时原样返回 totalRefundCent。
|
||||
// 注意:本函数只做“少退、挂起”,绝不多退,因此在任何路径下都不会造成租客损失或平台多付。
|
||||
func (o *RentalOrder) ApplyDepositHold(totalRefundCent, depositPortionCent int64) int64 {
|
||||
if !o.IsDepositHeld() {
|
||||
return totalRefundCent
|
||||
}
|
||||
withheld := depositPortionCent
|
||||
if withheld > totalRefundCent {
|
||||
withheld = totalRefundCent
|
||||
}
|
||||
if withheld <= 0 {
|
||||
return totalRefundCent
|
||||
}
|
||||
remainingDepositHoldCent := o.DepositAmountCent - o.DepositHoldAmountCent
|
||||
if remainingDepositHoldCent > 0 {
|
||||
newHold := withheld
|
||||
if newHold > remainingDepositHoldCent {
|
||||
newHold = remainingDepositHoldCent
|
||||
}
|
||||
o.DepositHoldAmountCent += newHold
|
||||
}
|
||||
return totalRefundCent - withheld
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package model
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestRentalOrderApplyDepositHold(t *testing.T) {
|
||||
order := RentalOrder{
|
||||
DepositAmountCent: 1000,
|
||||
DepositHoldStatus: DepositHoldStatusHeld,
|
||||
}
|
||||
|
||||
actualRefundCent := order.ApplyDepositHold(1500, 1000)
|
||||
if actualRefundCent != 500 {
|
||||
t.Fatalf("actual refund = %d, want 500", actualRefundCent)
|
||||
}
|
||||
if order.DepositHoldAmountCent != 1000 {
|
||||
t.Fatalf("hold amount = %d, want 1000", order.DepositHoldAmountCent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRentalOrderApplyDepositHoldKeepsWithholdingAfterAmountRecorded(t *testing.T) {
|
||||
order := RentalOrder{
|
||||
DepositAmountCent: 1000,
|
||||
DepositHoldStatus: DepositHoldStatusHeld,
|
||||
DepositHoldAmountCent: 1000,
|
||||
}
|
||||
|
||||
actualRefundCent := order.ApplyDepositHold(1500, 1000)
|
||||
if actualRefundCent != 500 {
|
||||
t.Fatalf("actual refund = %d, want 500", actualRefundCent)
|
||||
}
|
||||
if order.DepositHoldAmountCent != 1000 {
|
||||
t.Fatalf("hold amount = %d, want 1000", order.DepositHoldAmountCent)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRentalOrderApplyDepositHoldSkipsWhenNotHeld(t *testing.T) {
|
||||
order := RentalOrder{
|
||||
DepositAmountCent: 1000,
|
||||
DepositHoldStatus: DepositHoldStatusNone,
|
||||
}
|
||||
|
||||
actualRefundCent := order.ApplyDepositHold(1500, 1000)
|
||||
if actualRefundCent != 1500 {
|
||||
t.Fatalf("actual refund = %d, want 1500", actualRefundCent)
|
||||
}
|
||||
if order.DepositHoldAmountCent != 0 {
|
||||
t.Fatalf("hold amount = %d, want 0", order.DepositHoldAmountCent)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user