package order import ( "strings" "testing" "time" "hfb_sys/backend/internal/database" "hfb_sys/backend/internal/model" "hfb_sys/backend/internal/modules/rentergrowth" "hfb_sys/backend/internal/timeutil" "gorm.io/datatypes" ) func pureCoinDiscountOrder() model.RentalOrder { return model.RentalOrder{ 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 TestCalculateCheckoutSettlementUsesOnlyActualPureCoinForDiscount(t *testing.T) { tests := []struct { name string consumableAmountCent int64 coinConsumedM float64 wantPureCoinCent int64 wantDiscountCent int64 wantActualRentCent int64 wantOvershootCent int64 }{ { name: "全量纯币和额外物品", consumableAmountCent: 12000, coinConsumedM: 100, wantPureCoinCent: 26300, wantDiscountCent: 263, wantActualRentCent: 38037, wantOvershootCent: 0, }, { name: "部分纯币和全量额外物品", consumableAmountCent: 12000, coinConsumedM: 50, wantPureCoinCent: 13150, wantDiscountCent: 132, wantActualRentCent: 25018, wantOvershootCent: 0, }, { name: "只使用额外物品", consumableAmountCent: 12000, coinConsumedM: 0, wantPureCoinCent: 0, wantDiscountCent: 0, wantActualRentCent: 12000, wantOvershootCent: 0, }, { name: "纯币打超仍参与优惠", consumableAmountCent: 12000, coinConsumedM: 110, wantPureCoinCent: 28930, wantDiscountCent: 290, wantActualRentCent: 40640, wantOvershootCent: 2603, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { settlement := calculateCheckoutSettlement(pureCoinDiscountOrder(), test.consumableAmountCent, test.coinConsumedM, 0) if settlement.PureCoinAmountCent != test.wantPureCoinCent || settlement.PureCoinDiscountCent != test.wantDiscountCent { t.Fatalf("纯币原价/优惠 = %d/%d, want %d/%d", settlement.PureCoinAmountCent, settlement.PureCoinDiscountCent, test.wantPureCoinCent, test.wantDiscountCent) } if settlement.ActualRentAmountCent != test.wantActualRentCent || settlement.OvershootAmountCent != test.wantOvershootCent { t.Fatalf("实际租金/打超 = %d/%d, want %d/%d", settlement.ActualRentAmountCent, settlement.OvershootAmountCent, test.wantActualRentCent, test.wantOvershootCent) } }) } } func TestBuildOrderPricingDoesNotDiscountAllExtraItemOrder(t *testing.T) { pricing := buildOrderPricing( model.RentalListing{PriceCent: 12000}, model.GameAccount{AssetSummary: datatypes.JSON([]byte(`{ "price_breakdown": { "buyer_coin_base_price": 0, "seller_coin_base_price": 0, "consumable_price": 120, "seller_total_price": 120 } }`))}, ) if pricing.PureCoinAmountCent != 0 || pricing.ExtraItemAmountCent != 12000 || pricing.PureCoinPlatformFeeCent != 0 { t.Fatalf("全额外物品订单纯币/额外物品/纯币差价 = %d/%d/%d, want 0/12000/0", pricing.PureCoinAmountCent, pricing.ExtraItemAmountCent, pricing.PureCoinPlatformFeeCent) } if discount := rentergrowth.CalculateDiscountCent(pricing.PureCoinAmountCent, pricing.PureCoinPlatformFeeCent, 9900); discount != 0 { t.Fatalf("全额外物品订单优惠 = %d, want 0", discount) } } func TestCheckoutRefundsSiteRent(t *testing.T) { order := model.RentalOrder{ RentAmountCent: 8000, OwnerRentAmountCent: 8000, PlatformFeeCent: 0, BasePriceCent: 10000, ShelfRatioDelta: 25, DepositAmountCent: 1000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_coin_base_price": 80, "seller_coin_base_price": 80, "consumable_price": 0 } } }`)), } settlement := calculateCheckoutSettlement(order, 0, 100, 0) if settlement.RentRefundCent != 0 { t.Fatalf("full consume must not refund rent, rent refund = %d", settlement.RentRefundCent) } zeroUse := calculateCheckoutSettlement(order, 0, 0, 0) if zeroUse.RentRefundCent != 8000 { t.Fatalf("unused listing refunds site rent, got %d want 8000", zeroUse.RentRefundCent) } } func TestCalculateCheckoutSettlementRefundsUnusedRent(t *testing.T) { order := model.RentalOrder{ RentAmountCent: 38300, OwnerRentAmountCent: 35300, DepositAmountCent: 15000, 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, 700, 90, 0) // 角精度:243.7 = roundMoney(236.7 + 7) if settlement.ActualRentAmountCent != 24370 { t.Fatalf("ActualRentAmountCent = %d, want 24370", settlement.ActualRentAmountCent) } // 角精度:216.7 = roundMoney(209.7 + 7) 卖家币价+消耗品 if settlement.OwnerRentIncomeCent != 21670 { t.Fatalf("OwnerRentIncomeCent = %d, want 21670", settlement.OwnerRentIncomeCent) } // 角精度:27.0 = roundMoney(27) 平台费 if settlement.PlatformFeeCent != 2700 { t.Fatalf("PlatformFeeCent = %d, want 2700", settlement.PlatformFeeCent) } // 角精度:139.3 = roundMoney(383 - 243.7) if settlement.RentRefundCent != 13930 { t.Fatalf("RentRefundCent = %d, want 13930", settlement.RentRefundCent) } if settlement.DepositRefundCent != 15000 { t.Fatalf("DepositRefundCent = %d, want 15000", settlement.DepositRefundCent) } // 角精度:289.3 = roundMoney(139.3 + 150) if settlement.RenterRefundCent != 28930 { t.Fatalf("RenterRefundCent = %d, want 28930", settlement.RenterRefundCent) } } func TestCalculateCheckoutSettlementUsesBuyerAndSellerRatiosSeparately(t *testing.T) { order := model.RentalOrder{ RentAmountCent: 38300, OwnerRentAmountCent: 35300, DepositAmountCent: 15000, 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.ActualRentAmountCent != 13150 { t.Fatalf("租客侧实际租金 = %d, want 13150", settlement.ActualRentAmountCent) } // 角精度:116.5 = roundMoney(116.5) if settlement.OwnerRentIncomeCent != 11650 { t.Fatalf("卖家侧租金收入 = %d, want 11650", settlement.OwnerRentIncomeCent) } // 角精度:15.0 = roundMoney(15) if settlement.PlatformFeeCent != 1500 { t.Fatalf("平台差价 = %d, want 1500", settlement.PlatformFeeCent) } } func TestCalculateCheckoutSettlementAddsDepositCompensation(t *testing.T) { order := model.RentalOrder{ RentAmountCent: 38300, OwnerRentAmountCent: 35300, DepositAmountCent: 15000, 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, 12000, 100, 3000) if settlement.ActualRentAmountCent != 38300 { t.Fatalf("ActualRentAmountCent = %d, want 38300", settlement.ActualRentAmountCent) } if settlement.OwnerRentIncomeCent != 35300 { t.Fatalf("OwnerRentIncomeCent = %d, want 35300", settlement.OwnerRentIncomeCent) } if settlement.DepositCompensationCent != 3000 { t.Fatalf("DepositCompensationCent = %d, want 3000", settlement.DepositCompensationCent) } if settlement.OwnerIncomeCent != 38300 { t.Fatalf("OwnerIncomeCent = %d, want 38300", settlement.OwnerIncomeCent) } if settlement.RenterRefundCent != 12000 { t.Fatalf("RenterRefundCent = %d, want 12000", settlement.RenterRefundCent) } } func TestCalculateCheckoutSettlementAllowsOvershootFromDeposit(t *testing.T) { // 发布 100M,实际消耗 180M;按基价线性外推,打超从押金扣 order := model.RentalOrder{ RentAmountCent: 26300, // 仅币预收(无消耗品) OwnerRentAmountCent: 23300, DepositAmountCent: 30000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_coin_base_price": 263, "seller_coin_base_price": 233, "consumable_price": 0 } } }`)), } settlement := calculateCheckoutSettlement(order, 0, 180, 0) // 180/100 * 26300 = 47340 if settlement.ActualRentAmountCent != 47340 { t.Fatalf("ActualRentAmountCent = %d, want 47340", settlement.ActualRentAmountCent) } if settlement.OwnerRentIncomeCent != 41940 { // 180/100 * 23300 t.Fatalf("OwnerRentIncomeCent = %d, want 41940", settlement.OwnerRentIncomeCent) } if settlement.OvershootAmountCent != 21040 { // 47340 - 26300 t.Fatalf("OvershootAmountCent = %d, want 21040", settlement.OvershootAmountCent) } if settlement.ShortfallCent != 0 { t.Fatalf("ShortfallCent = %d, want 0", settlement.ShortfallCent) } if settlement.RentRefundCent != 0 { t.Fatalf("RentRefundCent = %d, want 0", settlement.RentRefundCent) } // 押金 30000 - 打超 21040 = 8960 if settlement.DepositRefundCent != 8960 { t.Fatalf("DepositRefundCent = %d, want 8960", settlement.DepositRefundCent) } } func TestCalculateCheckoutSettlementShortfallWhenDepositInsufficient(t *testing.T) { order := model.RentalOrder{ RentAmountCent: 26300, OwnerRentAmountCent: 23300, DepositAmountCent: 5000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_coin_base_price": 263, "seller_coin_base_price": 233, "consumable_price": 0 } } }`)), } settlement := calculateCheckoutSettlement(order, 0, 180, 0) // overshoot 21040, deposit 5000 → shortfall 16040 if settlement.OvershootAmountCent != 21040 { t.Fatalf("OvershootAmountCent = %d, want 21040", settlement.OvershootAmountCent) } if settlement.ShortfallCent != 16040 { t.Fatalf("ShortfallCent = %d, want 16040", settlement.ShortfallCent) } if settlement.DepositRefundCent != 0 { t.Fatalf("DepositRefundCent = %d, want 0", settlement.DepositRefundCent) } } func TestCalculateCheckoutSettlementUsesExplicitRatiosForActualConsume(t *testing.T) { // buyer 1:40, seller 1:45;消耗 180M // 租客: 180*100/40 = 450 元;号主: 180*100/45 = 400 元 order := model.RentalOrder{ RentAmountCent: 25000, // 100M 预收 OwnerRentAmountCent: 22222, DepositAmountCent: 50000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_ratio": 40, "seller_ratio": 45, "buyer_coin_base_price": 250, "seller_coin_base_price": 222.22, "consumable_price": 0 } } }`)), } settlement := calculateCheckoutSettlement(order, 0, 180, 0) if settlement.ActualRentAmountCent != 45000 { t.Fatalf("ActualRentAmountCent = %d, want 45000", settlement.ActualRentAmountCent) } if settlement.OwnerRentIncomeCent != 40000 { t.Fatalf("OwnerRentIncomeCent = %d, want 40000", settlement.OwnerRentIncomeCent) } if settlement.PlatformFeeCent != 5000 { t.Fatalf("PlatformFeeCent = %d, want 5000", settlement.PlatformFeeCent) } if settlement.OvershootAmountCent != 20000 { t.Fatalf("OvershootAmountCent = %d, want 20000", settlement.OvershootAmountCent) } if settlement.ShortfallCent != 0 { t.Fatalf("ShortfallCent = %d, want 0", settlement.ShortfallCent) } } func TestCalculateCheckoutSettlementCapsFullUseRatioRounding(t *testing.T) { // 发布量刚好用完时,比例换算的四舍五入不能把线下待打款抬高。 order := model.RentalOrder{ RentAmountCent: 37210, OwnerRentAmountCent: 34000, PlatformFeeCent: 3210, DepositAmountCent: 50000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 160000000, "asset_summary": { "price_breakdown": { "buyer_ratio": 43, "seller_ratio": 47, "buyer_coin_base_price": 372.1, "seller_coin_base_price": 340, "consumable_price": 0 } } }`)), } settlement := calculateCheckoutSettlement(order, 0, 160, 0) if settlement.ActualRentAmountCent != order.RentAmountCent { t.Fatalf("ActualRentAmountCent = %d, want %d", settlement.ActualRentAmountCent, order.RentAmountCent) } if settlement.OwnerRentIncomeCent != order.OwnerRentAmountCent { t.Fatalf("OwnerRentIncomeCent = %d, want %d", settlement.OwnerRentIncomeCent, order.OwnerRentAmountCent) } if settlement.PlatformFeeCent != order.PlatformFeeCent { t.Fatalf("PlatformFeeCent = %d, want %d", settlement.PlatformFeeCent, order.PlatformFeeCent) } if settlement.OvershootAmountCent != 0 { t.Fatalf("OvershootAmountCent = %d, want 0", settlement.OvershootAmountCent) } } func TestCalculateDepositWaiverUsesSharedRemainingQuota(t *testing.T) { paid, waived := calculateDepositWaiver(500, 300, 0) if paid != 200 || waived != 300 { t.Fatalf("paid = %d, waived = %d, want 200, 300", paid, waived) } paid, waived = calculateDepositWaiver(500, 300, 200) if paid != 400 || waived != 100 { t.Fatalf("paid = %d, waived = %d, want 400, 100", paid, waived) } paid, waived = calculateDepositWaiver(500, 300, 300) if paid != 500 || waived != 0 { t.Fatalf("paid = %d, waived = %d, want 500, 0", paid, waived) } } func TestArchiveAssetsMovesListingOffline(t *testing.T) { now := time.Now() listing := model.RentalListing{ Status: listingStatusRented, InTransaction: true, PublishedAt: &now, } account := model.GameAccount{Status: accountStatusRented} if err := archiveAssets(nil, &listing, &account); err != nil { t.Fatalf("archiveAssets: %v", err) } if listing.Status != listingStatusOffline { t.Fatalf("listing.Status = %q, want %q", listing.Status, listingStatusOffline) } if listing.InTransaction { t.Fatal("listing.InTransaction = true, want false") } if listing.PublishedAt != nil { t.Fatal("listing.PublishedAt is not nil") } if account.Status != accountStatusOffline { t.Fatalf("account.Status = %q, want %q", account.Status, accountStatusOffline) } } func TestCompleteAssetsMovesListingCompleted(t *testing.T) { now := time.Now() listing := model.RentalListing{ Status: listingStatusRented, InTransaction: true, PublishedAt: &now, } account := model.GameAccount{Status: accountStatusRented} if err := completeAssets(nil, &listing, &account); err != nil { t.Fatalf("completeAssets: %v", err) } if listing.Status != listingStatusCompleted { t.Fatalf("listing.Status = %q, want %q", listing.Status, listingStatusCompleted) } if listing.InTransaction { t.Fatal("listing.InTransaction = true, want false") } if listing.PublishedAt != nil { t.Fatal("listing.PublishedAt is not nil") } if account.Status != accountStatusOffline { t.Fatalf("account.Status = %q, want %q", account.Status, accountStatusOffline) } } 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) } } func TestApplyAdminOrderFiltersSmartRouting(t *testing.T) { db := database.NewDryRunDB() tests := []struct { name string query AdminOrderQuery wantSQLFrag string }{ { name: "11位手机号路由至users(phone)", query: AdminOrderQuery{Keyword: "13800138000"}, wantSQLFrag: "owner.phone = ? OR renter.phone = ?", }, { name: "RO前缀订单号路由至rental_orders(order_no)", query: AdminOrderQuery{Keyword: "RO202609051000"}, wantSQLFrag: "o.order_no = ?", }, { name: "12位时间计算的纯数字商品编号路由至rental_listings(listing_no)", query: AdminOrderQuery{Keyword: "202609040184"}, wantSQLFrag: "l.listing_no = ?", }, { name: "L前缀商品编号路由至rental_listings(listing_no)", query: AdminOrderQuery{Keyword: "L20260905100"}, wantSQLFrag: "l.listing_no = ?", }, { name: "短数字ID路由至主键及关联ID", query: AdminOrderQuery{Keyword: "12345"}, wantSQLFrag: "o.id = ? OR o.listing_id = ? OR o.owner_id = ? OR o.renter_id = ?", }, { name: "普通文字退回多列LIKE模糊匹配", query: AdminOrderQuery{Keyword: "测试账号"}, wantSQLFrag: "o.order_no LIKE ? OR l.listing_no LIKE ? OR a.title LIKE ? OR owner.phone LIKE ? OR renter.phone LIKE ?", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stmt := applyAdminOrderFilters(db.Table("rental_orders AS o"), tt.query).Find(&[]struct{}{}).Statement sql := stmt.SQL.String() if !strings.Contains(sql, tt.wantSQLFrag) { t.Fatalf("期望 SQL 包含 %q, 实际生成: %s", tt.wantSQLFrag, sql) } }) } } func TestCalculateCheckoutSettlement_NoPrepaidConsumable_OwnerGetsFullLoss(t *testing.T) { // 原订单无预收消耗品(consumable_price: 0),买家币价 263 元,卖家币价 233 元,平台加价 30 元 order := model.RentalOrder{ RentAmountCent: 26300, OwnerRentAmountCent: 23300, DepositAmountCent: 10000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_coin_base_price": 263, "seller_coin_base_price": 233, "consumable_price": 0 } } }`)), } // 结账时,耗币 100M(全额使用,原价 263/233),但号主后置申报了 50 元物资损耗(5000 分) settlement := calculateCheckoutSettlement(order, 5000, 100, 0) // 1. 租客实际承担租金 = 纯币 26300 + 损耗 5000 = 31300 if settlement.ActualRentAmountCent != 31300 { t.Fatalf("ActualRentAmountCent = %d, want 31300", settlement.ActualRentAmountCent) } // 2. 号主租金收益 = 纯币 23300 + 损耗 5000(全额划归号主) = 28300 if settlement.OwnerRentIncomeCent != 28300 { t.Fatalf("OwnerRentIncomeCent = %d, want 28300 (号主损耗必须全额划归号主)", settlement.OwnerRentIncomeCent) } // 3. 号主总收入必须包含全部损耗 if settlement.OwnerIncomeCent != 28300 { t.Fatalf("OwnerIncomeCent = %d, want 28300", settlement.OwnerIncomeCent) } // 4. 平台服务费必须保持原加价 3000(30 元),绝不能把号主的 50 元损耗吞掉! if settlement.PlatformFeeCent != 3000 { t.Fatalf("PlatformFeeCent = %d, want 3000 (平台绝不能从号主损耗中抽成)", settlement.PlatformFeeCent) } // 5. 打超金额 = 31300 - 26300 = 5000,从押金扣除 if settlement.OvershootAmountCent != 5000 { t.Fatalf("OvershootAmountCent = %d, want 5000", settlement.OvershootAmountCent) } // 押金 10000 - 5000 = 5000 退给租客 if settlement.DepositRefundCent != 5000 { t.Fatalf("DepositRefundCent = %d, want 5000", settlement.DepositRefundCent) } } func TestCalculateCheckoutSettlement_PrepaidConsumableOvershoot_OwnerGetsExcess(t *testing.T) { // 原订单有预收消耗品:买家预收 20 元,号主预收 16 元(平台抽 4 元);纯币 100 / 80 order := model.RentalOrder{ RentAmountCent: 12000, OwnerRentAmountCent: 9600, DepositAmountCent: 5000, AccountSnapshot: datatypes.JSON([]byte(`{ "haf_coin_amount": 100000000, "asset_summary": { "price_breakdown": { "buyer_coin_base_price": 100, "seller_coin_base_price": 80, "consumable_price": 20 } } }`)), } // 实际消耗品达到 50 元(5000 分),超出预收 30 元(3000 分) settlement := calculateCheckoutSettlement(order, 5000, 100, 0) // 号主预收部分 1600 + 超额损耗部分 3000 = 4600;纯币 8000;总号主租金 12600 if settlement.OwnerRentIncomeCent != 12600 { t.Fatalf("OwnerRentIncomeCent = %d, want 12600 (超出预收部分必须全额划归号主)", settlement.OwnerRentIncomeCent) } // 平台服务费仍为初始纯币差额 2000 + 预收消耗品差额 400 = 2400 if settlement.PlatformFeeCent != 2400 { t.Fatalf("PlatformFeeCent = %d, want 2400 (超额部分平台不抽成)", settlement.PlatformFeeCent) } } func TestApplyCheckoutPriceView_RoleIsolationAndPlatformFeeHidden(t *testing.T) { order := model.RentalOrder{ ID: 1, OwnerID: 100, RenterID: 200, RentAmountCent: 30000, OwnerRentAmountCent: 25000, DepositAmountCent: 10000, } rentCent := int64(30000) ownerRentCent := int64(25000) platformCent := int64(5000) renterRefundCent := int64(8000) ownerIncomeCent := int64(27000) checkout := model.OrderCheckout{ ID: 10, OrderID: 1, RentAmountCent: rentCent, OwnerRentAmountCent: ownerRentCent, PlatformFeeCent: platformCent, RenterRefundAmountCent: renterRefundCent, OwnerIncomeAmountCent: ownerIncomeCent, DepositDeductAmountCent: 2000, } // 1. 号主视角 ownerDTO := toCheckoutAdminDTO(checkout) applyCheckoutPriceView(&ownerDTO, order, 100) if ownerDTO.PlatformFeeCent != nil { t.Fatalf("号主视角必须屏蔽 PlatformFeeCent, 实际为: %v", *ownerDTO.PlatformFeeCent) } if ownerDTO.RenterRefundAmountCent != nil { t.Fatalf("号主视角必须屏蔽 RenterRefundAmountCent, 实际为: %v", *ownerDTO.RenterRefundAmountCent) } if ownerDTO.RentAmountCent != nil { t.Fatalf("号主视角必须屏蔽 RentAmountCent, 实际为: %v", *ownerDTO.RentAmountCent) } if ownerDTO.OwnerIncomeAmountCent == nil || *ownerDTO.OwnerIncomeAmountCent != 27000 { t.Fatalf("号主视角必须展示 OwnerIncomeAmountCent, 实际为: %v", ownerDTO.OwnerIncomeAmountCent) } // 2. 租客视角 renterDTO := toCheckoutAdminDTO(checkout) applyCheckoutPriceView(&renterDTO, order, 200) if renterDTO.PlatformFeeCent != nil { t.Fatalf("租客视角必须屏蔽 PlatformFeeCent, 实际为: %v", *renterDTO.PlatformFeeCent) } if renterDTO.OwnerRentAmountCent != nil { t.Fatalf("租客视角必须屏蔽 OwnerRentAmountCent, 实际为: %v", *renterDTO.OwnerRentAmountCent) } if renterDTO.OwnerIncomeAmountCent != nil { t.Fatalf("租客视角必须屏蔽 OwnerIncomeAmountCent, 实际为: %v", *renterDTO.OwnerIncomeAmountCent) } if renterDTO.RenterRefundAmountCent == nil || *renterDTO.RenterRefundAmountCent != 8000 { t.Fatalf("租客视角必须展示 RenterRefundAmountCent, 实际为: %v", renterDTO.RenterRefundAmountCent) } }