refactor(order): 结算优先读取整数分快照

This commit is contained in:
yml2213
2026-10-30 14:59:47 +08:00
parent 98d0d35830
commit 13a3127abc
2 changed files with 133 additions and 11 deletions
+65 -11
View File
@@ -161,19 +161,19 @@ func estimateOrderDurationHours(snapshot datatypes.JSON) int {
func buildOrderPricing(listing model.RentalListing, account model.GameAccount) orderPricing {
rentAmountCent := listing.PriceCent
ownerRentAmountCent := int64(math.Round(readSnapshotPrice(account.AssetSummary, "seller_total_price") * 100))
ownerRentAmountCent := readSnapshotCent(account.AssetSummary, "seller_total_price")
if ownerRentAmountCent <= 0 || ownerRentAmountCent > rentAmountCent {
ownerRentAmountCent = rentAmountCent
}
platformFeeCent := int64(math.Round(readSnapshotPrice(account.AssetSummary, "platform_markup_amount") * 100))
platformFeeCent := readSnapshotCent(account.AssetSummary, "platform_markup_amount")
if platformFeeCent <= 0 || ownerRentAmountCent+platformFeeCent != rentAmountCent {
platformFeeCent = rentAmountCent - ownerRentAmountCent
}
if platformFeeCent < 0 {
platformFeeCent = 0
}
pureCoinAmountCent := int64(math.Round(readSnapshotPrice(account.AssetSummary, "buyer_coin_base_price") * 100))
extraItemSnapshotCent := int64(math.Round(readSnapshotPrice(account.AssetSummary, "consumable_price") * 100))
pureCoinAmountCent := readSnapshotCent(account.AssetSummary, "buyer_coin_base_price")
extraItemSnapshotCent := readSnapshotCent(account.AssetSummary, "consumable_price")
if pureCoinAmountCent <= 0 {
if extraItemSnapshotCent > 0 && extraItemSnapshotCent <= rentAmountCent {
pureCoinAmountCent = rentAmountCent - extraItemSnapshotCent
@@ -185,7 +185,7 @@ func buildOrderPricing(listing model.RentalListing, account model.GameAccount) o
pureCoinAmountCent = rentAmountCent
}
extraItemAmountCent := maxCent(rentAmountCent-pureCoinAmountCent, 0)
ownerPureCoinAmountCent := int64(math.Round(readSnapshotPrice(account.AssetSummary, "seller_coin_base_price") * 100))
ownerPureCoinAmountCent := readSnapshotCent(account.AssetSummary, "seller_coin_base_price")
if ownerPureCoinAmountCent <= 0 || ownerPureCoinAmountCent > ownerRentAmountCent {
ownerPureCoinAmountCent = maxCent(ownerRentAmountCent-minCent(extraItemAmountCent, ownerRentAmountCent), 0)
}
@@ -207,18 +207,72 @@ func readSnapshotPrice(raw datatypes.JSON, key string) float64 {
return readOrderSnapshotPrice(raw, key)
}
func readOrderSnapshotPrice(raw datatypes.JSON, key string) float64 {
if len(raw) == 0 {
// readSnapshotCent 优先读取 price_breakdown 的整数分字段,缺失时兼容旧元字段。
func readSnapshotCent(raw datatypes.JSON, key string) int64 {
return readOrderSnapshotCent(raw, key)
}
func readOrderSnapshotCent(raw datatypes.JSON, key string) int64 {
breakdown, ok := readOrderSnapshotBreakdown(raw)
if !ok {
return 0
}
if cent := readJSONInt64(breakdown[key+"_cent"]); cent > 0 {
return cent
}
legacy := readJSONNumber(breakdown[key])
if legacy <= 0 {
return 0
}
return int64(math.Round(legacy * 100))
}
func readOrderSnapshotBreakdown(raw datatypes.JSON) (map[string]any, bool) {
if len(raw) == 0 {
return nil, false
}
var snapshot map[string]any
if err := json.Unmarshal(raw, &snapshot); err != nil {
return 0
return nil, false
}
if assetSummary, ok := snapshot["asset_summary"].(map[string]any); ok {
snapshot = assetSummary
}
breakdown, ok := snapshot["price_breakdown"].(map[string]any)
return breakdown, ok
}
func readJSONInt64(value any) int64 {
switch typed := value.(type) {
case float64:
return int64(typed)
case float32:
return int64(typed)
case int:
return int64(typed)
case int64:
return typed
case int32:
return int64(typed)
case json.Number:
number, err := typed.Int64()
if err != nil {
return 0
}
return number
case string:
number, err := strconv.ParseInt(typed, 10, 64)
if err != nil {
return 0
}
return number
default:
return 0
}
}
func readOrderSnapshotPrice(raw datatypes.JSON, key string) float64 {
breakdown, ok := readOrderSnapshotBreakdown(raw)
if !ok {
return 0
}
@@ -313,7 +367,7 @@ func calculateCheckoutSettlement(order model.RentalOrder, consumableAmountCent i
orderDepositAmountCent := order.DepositAmountCent
buyerCoinBasePriceCent := orderPureCoinOriginalAmountCent(order)
sellerCoinBasePriceCent := int64(math.Round(readOrderSnapshotPrice(order.AccountSnapshot, "seller_coin_base_price") * 100))
sellerCoinBasePriceCent := readOrderSnapshotCent(order.AccountSnapshot, "seller_coin_base_price")
if sellerCoinBasePriceCent <= 0 || sellerCoinBasePriceCent > orderOwnerRentAmountCent {
ownerExtraItemCent := minCent(orderExtraItemOriginalAmountCent(order), orderOwnerRentAmountCent)
sellerCoinBasePriceCent = maxCent(orderOwnerRentAmountCent-ownerExtraItemCent, 0)
@@ -427,11 +481,11 @@ func orderPureCoinOriginalAmountCent(order model.RentalOrder) int64 {
if order.ExtraItemOriginalAmountCent > 0 {
return maxCent(originalRentCent-minCent(order.ExtraItemOriginalAmountCent, originalRentCent), 0)
}
pureCoinCent := int64(math.Round(readOrderSnapshotPrice(order.AccountSnapshot, "buyer_coin_base_price") * 100))
pureCoinCent := readOrderSnapshotCent(order.AccountSnapshot, "buyer_coin_base_price")
if pureCoinCent > 0 && pureCoinCent <= originalRentCent {
return pureCoinCent
}
extraItemCent := int64(math.Round(readOrderSnapshotPrice(order.AccountSnapshot, "consumable_price") * 100))
extraItemCent := readOrderSnapshotCent(order.AccountSnapshot, "consumable_price")
if extraItemCent > 0 && extraItemCent <= originalRentCent {
return originalRentCent - extraItemCent
}
@@ -0,0 +1,68 @@
package order
import (
"testing"
"hfb_sys/backend/internal/model"
"gorm.io/datatypes"
)
func TestReadOrderSnapshotCentPrefersCentField(t *testing.T) {
raw := datatypes.JSON([]byte(`{
"asset_summary": {
"price_breakdown": {
"seller_total_price": 353.00,
"seller_total_price_cent": 35301
}
}
}`))
if got := readSnapshotCent(raw, "seller_total_price"); got != 35301 {
t.Fatalf("优先读取分字段失败: got %d, want 35301", got)
}
}
func TestReadOrderSnapshotCentFallsBackToLegacyYuan(t *testing.T) {
raw := datatypes.JSON([]byte(`{
"asset_summary": {
"price_breakdown": {
"consumable_price": 120.00
}
}
}`))
if got := readSnapshotCent(raw, "consumable_price"); got != 12000 {
t.Fatalf("旧元字段回退失败: got %d, want 12000", got)
}
}
func TestBuildOrderPricingUsesCentBreakdown(t *testing.T) {
account := model.GameAccount{
AssetSummary: datatypes.JSON([]byte(`{
"asset_summary": {
"price_breakdown": {
"seller_total_price_cent": 35301,
"platform_markup_amount_cent": 2999,
"buyer_coin_base_price_cent": 26315,
"consumable_price_cent": 12000,
"seller_coin_base_price_cent": 23315
}
}
}`)),
}
pricing := buildOrderPricing(model.RentalListing{PriceCent: 38300}, account)
if pricing.OwnerRentAmountCent != 35301 {
t.Fatalf("OwnerRentAmountCent = %d, want 35301", pricing.OwnerRentAmountCent)
}
if pricing.PlatformFeeCent != 2999 {
t.Fatalf("PlatformFeeCent = %d, want 2999", pricing.PlatformFeeCent)
}
if pricing.PureCoinAmountCent != 26315 {
t.Fatalf("PureCoinAmountCent = %d, want 26315", pricing.PureCoinAmountCent)
}
if pricing.ExtraItemAmountCent != 11985 {
t.Fatalf("ExtraItemAmountCent = %d, want 11985", pricing.ExtraItemAmountCent)
}
if pricing.OwnerPureCoinAmountCent != 23315 {
t.Fatalf("OwnerPureCoinAmountCent = %d, want 23315", pricing.OwnerPureCoinAmountCent)
}
}