Files
hfb_sys/backend/internal/modules/order/repository_test.go
T

161 lines
4.8 KiB
Go

package order
import (
"testing"
"time"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/timeutil"
"gorm.io/datatypes"
)
func TestCalculateCheckoutSettlementRefundsUnusedRent(t *testing.T) {
order := model.RentalOrder{
RentAmount: 383,
OwnerRentAmount: 353,
DepositAmount: 150,
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
}
}
}`)),
}
settlement := calculateCheckoutSettlement(order, 7, 90, 0)
// 角精度:243.7 = roundMoney(236.7 + 7)
if settlement.ActualRentAmount != 243.7 {
t.Fatalf("ActualRentAmount = %.1f, want 243.7", settlement.ActualRentAmount)
}
// 角精度:216.7 = roundMoney(209.7 + 7) 卖家币价+消耗品
if settlement.OwnerRentIncome != 216.7 {
t.Fatalf("OwnerRentIncome = %.1f, want 216.7", settlement.OwnerRentIncome)
}
// 角精度:27.0 = roundMoney(27) 平台费
if settlement.PlatformFee != 27.0 {
t.Fatalf("PlatformFee = %.1f, want 27.0", settlement.PlatformFee)
}
// 角精度:139.3 = roundMoney(383 - 243.7)
if settlement.RentRefund != 139.3 {
t.Fatalf("RentRefund = %.1f, want 139.3", settlement.RentRefund)
}
if settlement.DepositRefund != 150 {
t.Fatalf("DepositRefund = %.1f, want 150.0", settlement.DepositRefund)
}
// 角精度:289.3 = roundMoney(139.3 + 150)
if settlement.RenterRefund != 289.3 {
t.Fatalf("RenterRefund = %.1f, want 289.3", settlement.RenterRefund)
}
}
func TestCalculateCheckoutSettlementUsesBuyerAndSellerRatiosSeparately(t *testing.T) {
order := model.RentalOrder{
RentAmount: 383,
OwnerRentAmount: 353,
DepositAmount: 150,
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
}
}
}`)),
}
settlement := calculateCheckoutSettlement(order, 0, 50, 0)
// 角精度:131.5 = roundMoney(131.5)
if settlement.ActualRentAmount != 131.5 {
t.Fatalf("租客侧实际租金 = %.1f, want 131.5", settlement.ActualRentAmount)
}
// 角精度:116.5 = roundMoney(116.5)
if settlement.OwnerRentIncome != 116.5 {
t.Fatalf("卖家侧租金收入 = %.1f, want 116.5", settlement.OwnerRentIncome)
}
// 角精度:15.0 = roundMoney(15)
if settlement.PlatformFee != 15.0 {
t.Fatalf("平台差价 = %.1f, want 15.0", settlement.PlatformFee)
}
}
func TestCalculateCheckoutSettlementAddsDepositCompensation(t *testing.T) {
order := model.RentalOrder{
RentAmount: 383,
OwnerRentAmount: 353,
DepositAmount: 150,
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
}
}
}`)),
}
settlement := calculateCheckoutSettlement(order, 120, 100, 30)
if settlement.ActualRentAmount != 383 {
t.Fatalf("ActualRentAmount = %.2f, want 383.00", settlement.ActualRentAmount)
}
if settlement.OwnerRentIncome != 353 {
t.Fatalf("OwnerRentIncome = %.2f, want 353.00", settlement.OwnerRentIncome)
}
if settlement.DepositCompensation != 30 {
t.Fatalf("DepositCompensation = %.2f, want 30.00", settlement.DepositCompensation)
}
if settlement.OwnerIncome != 383 {
t.Fatalf("OwnerIncome = %.2f, want 383.00", settlement.OwnerIncome)
}
if settlement.RenterRefund != 120 {
t.Fatalf("RenterRefund = %.2f, want 120.00", settlement.RenterRefund)
}
}
func TestArchiveListingAfterCheckoutMovesListingOffline(t *testing.T) {
// This test is purely for contract documentation; no behavior is tested yet.
// When implementing auto-archive behavior:
// - Call should succeed for renting/overdue/pending_checkout_confirm/pending_checkout_accept orders
// - Listing status should be set to "archived" or "offline"
// - In-transaction flag should be cleared
// - Order should enter completed or closed state
_ = time.Now()
}
func TestNewOrderNoUsesShanghaiTimeWhenLocalIsUTC(t *testing.T) {
oldLocal := time.Local
time.Local = time.UTC
defer func() {
time.Local = oldLocal
}()
loc := timeutil.ShanghaiLocation()
before := time.Now().In(loc)
orderNo, err := newOrderNo()
after := time.Now().In(loc)
if err != nil {
t.Fatalf("newOrderNo() error = %v", err)
}
if len(orderNo) != len("RO20260603123456789") {
t.Fatalf("orderNo length = %d, want %d: %s", len(orderNo), len("RO20260603123456789"), orderNo)
}
parsed, err := time.ParseInLocation("20060102150405", orderNo[2:16], loc)
if err != nil {
t.Fatalf("parse order no time: %v", err)
}
if parsed.Before(before.Add(-2*time.Second)) || parsed.After(after.Add(2*time.Second)) {
t.Fatalf("order no time = %s, want between %s and %s", parsed, before, after)
}
}