feat(distribution): 分站收号压价解耦买家价(方案 B 新口径)
核心语义反转:receive_cost_delta 为压价点数,收号比例 = 主站参考比例 R + 点数, 点数越大号主收号价越低;买家售价锚定主站参考比例推导,不再随收号价联动。 - 迁移 000072:distribution_sites 新增 receive_cost_delta(旧 receive_ratio_delta 保留只读) - receive_pricing:新增 Normalize/ApplySiteReceiveCostDelta;分站定价买家侧改用 R 锚点(referenceSellerCoinBasePrice),快照写入 site_receive_cost_delta 与 pricing_model 标记 - site_receive:新增 resolveSiteReceiveCostDelta 读取链路,旧 ResolveReceiveRatioDelta 保留 - 分成不变:压价差经结算层 profit 自动进入 35/40/25 三方分成池; 货架自主加价仍 100% 归分站,两条边界均以主站为锚 - 权限对齐旧字段:主站全局管理员与分站操作员均可设置 - 前端三端同步:主站 pricing.ts/usePricingCalculator 买卖解耦试算、 主站后台弹窗改「收号压价」价格语义文案、分销后台 SiteSettings 同步 - 测试:单测锚定 R=43 时 cost_delta=3 → 收号 217.4 / 卖价 263.2 不变 / markup 池 30.6→54.9
This commit is contained in:
@@ -36,7 +36,7 @@ func ReceivePricingFromAssetSummary(raw datatypes.JSON) ReceivePricingView {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) applyMainSiteReceivePricing(ctx context.Context, req *CreateRequest, receiveRatioDelta float64, onDistributionSite bool) error {
|
||||
func (s *Service) applyMainSiteReceivePricing(ctx context.Context, req *CreateRequest, receiveRatioDelta, receiveCostDelta float64, onDistributionSite bool) error {
|
||||
if req == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -48,11 +48,12 @@ func (s *Service) applyMainSiteReceivePricing(ctx context.Context, req *CreateRe
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
applyMainSiteReceivePricing(req, options, config, receiveRatioDelta, onDistributionSite)
|
||||
applyMainSiteReceivePricing(req, options, config, receiveRatioDelta, receiveCostDelta, onDistributionSite)
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.PublishOptionsDTO, config salePriceConfig, receiveRatioDelta float64, onDistributionSite bool) {
|
||||
func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.PublishOptionsDTO, config salePriceConfig, receiveRatioDelta, receiveCostDelta float64, onDistributionSite bool) {
|
||||
|
||||
if req == nil {
|
||||
return
|
||||
}
|
||||
@@ -70,18 +71,20 @@ func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.Publis
|
||||
if requestedRatio <= 0 {
|
||||
requestedRatio = readSummaryNumber(breakdown["accelerated_sale_ratio"])
|
||||
}
|
||||
costDelta := NormalizeSiteReceiveCostDelta(receiveCostDelta)
|
||||
ratioDelta := NormalizeSiteReceiveRatioDelta(receiveRatioDelta)
|
||||
sellerRatio := clampSaleRatio(referenceRatio, requestedRatio)
|
||||
delta := NormalizeSiteReceiveRatioDelta(receiveRatioDelta)
|
||||
// 分站新口径:收号比例 = R + 压价点数(收号价更低),买家定价锚定主站参考比例 R,不随收号价联动。
|
||||
if onDistributionSite {
|
||||
sellerRatio = ApplySiteReceiveRatioDelta(referenceRatio, delta)
|
||||
sellerRatio = ApplySiteReceiveCostDelta(referenceRatio, costDelta)
|
||||
}
|
||||
coinWan := coinM * 100
|
||||
sellerCoinBasePrice := roundMoney(coinWan / sellerRatio)
|
||||
consumablePrice := consumableValue(req.AssetSummary)
|
||||
sellerTotalPrice := roundMoney(sellerCoinBasePrice + consumablePrice)
|
||||
dailyLoss := readSummaryNumber(req.AssetSummary["daily_loss_m"])
|
||||
pricing := calculateExternalPlatformPricing(coinM, sellerRatio, sellerCoinBasePrice, consumablePrice, config)
|
||||
|
||||
// 买家价始终按主站口径推导:分站只改收号侧,卖价与主站同基准(压价差进入三方分成池)。
|
||||
pricing := calculateExternalPlatformPricing(coinM, referenceRatio, referenceSellerCoinBasePrice(coinWan, referenceRatio), consumablePrice, config)
|
||||
breakdown["seller_reference_ratio"] = referenceRatio
|
||||
breakdown["seller_ratio"] = sellerRatio
|
||||
breakdown["seller_coin_base_price"] = sellerCoinBasePrice
|
||||
@@ -89,7 +92,12 @@ func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.Publis
|
||||
breakdown["consumable_price"] = consumablePrice
|
||||
breakdown["daily_loss_ratio_adjustment"] = calculateDailyLossRatioAdjustment(dailyLoss)
|
||||
breakdown["accelerated_sale_ratio"] = sellerRatio
|
||||
breakdown["site_receive_ratio_delta"] = delta
|
||||
if onDistributionSite {
|
||||
breakdown["site_receive_cost_delta"] = costDelta
|
||||
breakdown["pricing_model"] = "site_cost_decoupled_v1"
|
||||
} else {
|
||||
breakdown["site_receive_ratio_delta"] = ratioDelta
|
||||
}
|
||||
breakdown["buyer_coin_base_price"] = pricing.BuyerCoinBasePrice
|
||||
breakdown["buyer_total_price"] = pricing.BuyerTotalPrice
|
||||
breakdown["buyer_ratio"] = pricing.BuyerRatio
|
||||
@@ -100,6 +108,36 @@ func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.Publis
|
||||
req.PriceCent = yuanToCent(pricing.BuyerTotalPrice)
|
||||
}
|
||||
|
||||
// NormalizeSiteReceiveCostDelta 将分站收号压价点数限制在 [0, 20]。
|
||||
// 点数越大,分站收号比例越高(相对主站参考比例),收号价越低;0 表示与主站同价收号。
|
||||
func NormalizeSiteReceiveCostDelta(delta float64) float64 {
|
||||
if delta < 0 || math.IsNaN(delta) || math.IsInf(delta, 0) {
|
||||
return 0
|
||||
}
|
||||
if delta > maxSiteReceiveRatioDelta {
|
||||
return maxSiteReceiveRatioDelta
|
||||
}
|
||||
return roundRatio(delta)
|
||||
}
|
||||
|
||||
// ApplySiteReceiveCostDelta 按新口径计算分站收号比例:R + 压价点数(收号价更低)。
|
||||
// 与旧 ApplySiteReceiveRatioDelta 相反方向,买家价已解耦、不再从收号比例推导。
|
||||
func ApplySiteReceiveCostDelta(referenceRatio, delta float64) float64 {
|
||||
if referenceRatio <= 0 {
|
||||
return 0
|
||||
}
|
||||
siteRatio := roundRatio(referenceRatio + NormalizeSiteReceiveCostDelta(delta))
|
||||
return siteRatio
|
||||
}
|
||||
|
||||
// referenceSellerCoinBasePrice 计算主站参考比例下的号主基础价,用作买家定价锚点。
|
||||
func referenceSellerCoinBasePrice(coinWan, referenceRatio float64) float64 {
|
||||
if referenceRatio <= 0 {
|
||||
return 0
|
||||
}
|
||||
return roundMoney(coinWan / referenceRatio)
|
||||
}
|
||||
|
||||
// NormalizeSiteReceiveRatioDelta 将分站收号下调点数限制在 [0, 20]。
|
||||
func NormalizeSiteReceiveRatioDelta(delta float64) float64 {
|
||||
if delta < 0 || math.IsNaN(delta) || math.IsInf(delta, 0) {
|
||||
|
||||
Reference in New Issue
Block a user