按实际纯币金额计算租客优惠与积分
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package dispute
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -8,9 +10,36 @@ import (
|
||||
"hfb_sys/backend/internal/database"
|
||||
"hfb_sys/backend/internal/model"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func disputePureCoinOrder() model.RentalOrder {
|
||||
return model.RentalOrder{
|
||||
Status: "renting",
|
||||
HandoffStatus: "received",
|
||||
SettlementStatus: "unsettled",
|
||||
RentAmountCent: 38037,
|
||||
OwnerRentAmountCent: 35300,
|
||||
DepositAmountCent: 15000,
|
||||
RentOriginalAmountCent: 38300,
|
||||
RentDiscountAmountCent: 263,
|
||||
PureCoinOriginalAmountCent: 26300,
|
||||
ExtraItemOriginalAmountCent: 12000,
|
||||
RenterDiscountBps: 9900,
|
||||
AccountSnapshot: datatypes.JSON([]byte(`{
|
||||
"haf_coin_amount": 100000000,
|
||||
"asset_summary": {
|
||||
"price_breakdown": {
|
||||
"buyer_coin_base_price": 263,
|
||||
"seller_coin_base_price": 233,
|
||||
"consumable_price": 120
|
||||
}
|
||||
}
|
||||
}`)),
|
||||
}
|
||||
}
|
||||
|
||||
func setupDisputeTestDB(t *testing.T) *gorm.DB {
|
||||
t.Helper()
|
||||
db := database.NewTestDB()
|
||||
@@ -261,10 +290,12 @@ func TestPlatformManagedArbitrationUsesOfflineSettlement(t *testing.T) {
|
||||
if adminNotificationCount == 0 {
|
||||
t.Fatal("platform managed dispute should notify managed admin")
|
||||
}
|
||||
actualCoinConsumedM := 0.0
|
||||
|
||||
if _, err := repo.Arbitrate(t.Context(), adminID, created.ID, ArbitrateRequest{
|
||||
Result: "release_deposit",
|
||||
Remark: "确认租金给卖家,线下结算",
|
||||
Result: "release_deposit",
|
||||
Remark: "确认租金给卖家,线下结算",
|
||||
ActualCoinConsumedM: &actualCoinConsumedM,
|
||||
}, AuditMeta{}); err != nil {
|
||||
t.Fatalf("仲裁失败: %v", err)
|
||||
}
|
||||
@@ -291,6 +322,90 @@ func TestPlatformManagedArbitrationUsesOfflineSettlement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestArbitrationCompletedOrderRequiresActualCoinConsumedM(t *testing.T) {
|
||||
db := setupDisputeTestDB(t)
|
||||
repo := NewRepository(db, Dependencies{RefundStarter: RefundStarterFunc(func(context.Context, uint64, int64, string, string) (string, error) {
|
||||
return "refunded", nil
|
||||
})})
|
||||
_, renter, order := createDisputeOrderFixture(t, db, disputePureCoinOrder())
|
||||
created, err := repo.Create(t.Context(), renter.ID, order.ID, CreateRequest{
|
||||
Type: "haf_coin_dispute",
|
||||
Description: "核对最终哈夫币消耗",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("创建申诉失败: %v", err)
|
||||
}
|
||||
|
||||
_, err = repo.Arbitrate(t.Context(), 77, created.ID, ArbitrateRequest{
|
||||
Result: "release_deposit",
|
||||
Remark: "确认完成订单",
|
||||
}, AuditMeta{})
|
||||
if !errors.Is(err, ErrInvalidDispute) {
|
||||
t.Fatalf("缺少实际消耗 M 的仲裁错误 = %v, want ErrInvalidDispute", err)
|
||||
}
|
||||
|
||||
actualCoinConsumedM := 50.0
|
||||
if _, err := repo.Arbitrate(t.Context(), 77, created.ID, ArbitrateRequest{
|
||||
Result: "release_deposit",
|
||||
Remark: "确认实际消耗 50M",
|
||||
ActualCoinConsumedM: &actualCoinConsumedM,
|
||||
}, AuditMeta{}); err != nil {
|
||||
t.Fatalf("带实际消耗 M 仲裁失败: %v", err)
|
||||
}
|
||||
var saved model.RentalOrder
|
||||
if err := db.First(&saved, order.ID).Error; err != nil {
|
||||
t.Fatalf("读取订单失败: %v", err)
|
||||
}
|
||||
if saved.ActualCoinConsumedM != 50 || saved.ActualPureCoinAmountCent != 13150 || saved.GrowthPointsAwarded != 131 {
|
||||
t.Fatalf("最终 M/纯币/积分 = %.2f/%d/%d, want 50/13150/131", saved.ActualCoinConsumedM, saved.ActualPureCoinAmountCent, saved.GrowthPointsAwarded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckoutDisputeArbitrationReusesCheckoutCoinConsumedM(t *testing.T) {
|
||||
db := setupDisputeTestDB(t)
|
||||
repo := NewRepository(db, Dependencies{RefundStarter: RefundStarterFunc(func(context.Context, uint64, int64, string, string) (string, error) {
|
||||
return "refunded", nil
|
||||
})})
|
||||
inputOrder := disputePureCoinOrder()
|
||||
inputOrder.Status = "pending_checkout_confirm"
|
||||
inputOrder.HandoffStatus = "pending_owner_checkout"
|
||||
inputOrder.SettlementStatus = "pending"
|
||||
_, renter, order := createDisputeOrderFixture(t, db, inputOrder)
|
||||
checkout := model.OrderCheckout{
|
||||
OrderID: order.ID,
|
||||
InitiatedBy: renter.ID,
|
||||
Status: "submitted",
|
||||
CoinConsumedM: 25,
|
||||
}
|
||||
if err := db.Create(&checkout).Error; err != nil {
|
||||
t.Fatalf("创建结账记录失败: %v", err)
|
||||
}
|
||||
created, err := repo.Create(t.Context(), renter.ID, order.ID, CreateRequest{
|
||||
Type: "checkout_amount",
|
||||
Description: "结账金额有争议",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("创建结账争议失败: %v", err)
|
||||
}
|
||||
if created.CheckoutID == nil || *created.CheckoutID != checkout.ID || created.CheckoutCoinConsumedM == nil || *created.CheckoutCoinConsumedM != 25 {
|
||||
t.Fatalf("关联结账/M = %v/%v, want %d/25", created.CheckoutID, created.CheckoutCoinConsumedM, checkout.ID)
|
||||
}
|
||||
|
||||
if _, err := repo.Arbitrate(t.Context(), 77, created.ID, ArbitrateRequest{
|
||||
Result: "release_deposit",
|
||||
Remark: "沿用双方结账消耗",
|
||||
}, AuditMeta{}); err != nil {
|
||||
t.Fatalf("仲裁复用结账 M 失败: %v", err)
|
||||
}
|
||||
var saved model.RentalOrder
|
||||
if err := db.First(&saved, order.ID).Error; err != nil {
|
||||
t.Fatalf("读取订单失败: %v", err)
|
||||
}
|
||||
if saved.ActualCoinConsumedM != 25 || saved.ActualPureCoinAmountCent != 6575 || saved.GrowthPointsAwarded != 65 {
|
||||
t.Fatalf("最终 M/纯币/积分 = %.2f/%d/%d, want 25/6575/65", saved.ActualCoinConsumedM, saved.ActualPureCoinAmountCent, saved.GrowthPointsAwarded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildArbitrationSettlementSkipsFrozenReleaseWhenNoFrozenBalance(t *testing.T) {
|
||||
order := model.RentalOrder{
|
||||
ID: 11,
|
||||
|
||||
Reference in New Issue
Block a user