Files
hfb_sys/backend/internal/modules/listing/site_receive.go
T
yml2213 22fcaa5945 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
2026-09-17 15:54:56 +08:00

90 lines
3.0 KiB
Go

package listing
import (
"context"
"strings"
"hfb_sys/backend/internal/model"
)
// ReceiveCostDeltaBySiteCode 读取分站收号压价点数(新口径,收号比例 = R + 点数)。
func (r *Repository) ReceiveCostDeltaBySiteCode(ctx context.Context, siteCode string) float64 {
siteCode = strings.TrimSpace(siteCode)
if r == nil || r.db == nil || siteCode == "" {
return 0
}
var delta float64
_ = r.db.WithContext(ctx).Model(&model.DistributionSite{}).
Select("COALESCE(receive_cost_delta, 0)").
Where("site_code = ? AND status = 'active'", siteCode).
Limit(1).
Scan(&delta)
return NormalizeSiteReceiveCostDelta(delta)
}
// resolveSiteReceiveCostDelta 按站点编码或商品归属站点解析压价点数。
// 返回 onDistribution 表示当前上下文是否为分站(false 时压价不生效)。
func (r *Repository) resolveSiteReceiveCostDelta(ctx context.Context, listingID uint64, siteCode string) (float64, bool) {
if code := strings.TrimSpace(siteCode); code != "" {
return r.ReceiveCostDeltaBySiteCode(ctx, code), true
}
if r == nil || r.db == nil || listingID == 0 {
return 0, false
}
var siteID *uint64
if err := r.db.WithContext(ctx).Model(&model.RentalListing{}).
Select("distribution_site_id").
Where("id = ?", listingID).
Limit(1).
Scan(&siteID).Error; err != nil || siteID == nil || *siteID == 0 {
return 0, false
}
var delta float64
_ = r.db.WithContext(ctx).Model(&model.DistributionSite{}).
Select("COALESCE(receive_cost_delta, 0)").
Where("id = ? AND status = 'active'", *siteID).
Limit(1).
Scan(&delta)
return NormalizeSiteReceiveCostDelta(delta), true
}
// ReceiveRatioDeltaBySiteCode 旧口径(加价抢货)读取,保留只读兼容。
func (r *Repository) ReceiveRatioDeltaBySiteCode(ctx context.Context, siteCode string) float64 {
siteCode = strings.TrimSpace(siteCode)
if r == nil || r.db == nil || siteCode == "" {
return 0
}
var delta float64
_ = r.db.WithContext(ctx).Model(&model.DistributionSite{}).
Select("COALESCE(receive_ratio_delta, 0)").
Where("site_code = ? AND status = 'active'", siteCode).
Limit(1).
Scan(&delta)
return NormalizeSiteReceiveRatioDelta(delta)
}
// ResolveReceiveRatioDelta 旧口径解析入口,保留供旧快照读侧使用。
func (r *Repository) ResolveReceiveRatioDelta(ctx context.Context, listingID uint64, siteCode string) (float64, bool) {
if code := strings.TrimSpace(siteCode); code != "" {
return r.ReceiveRatioDeltaBySiteCode(ctx, code), true
}
if r == nil || r.db == nil || listingID == 0 {
return 0, false
}
var siteID *uint64
if err := r.db.WithContext(ctx).Model(&model.RentalListing{}).
Select("distribution_site_id").
Where("id = ?", listingID).
Limit(1).
Scan(&siteID).Error; err != nil || siteID == nil || *siteID == 0 {
return 0, false
}
var delta float64
_ = r.db.WithContext(ctx).Model(&model.DistributionSite{}).
Select("COALESCE(receive_ratio_delta, 0)").
Where("id = ? AND status = 'active'", *siteID).
Limit(1).
Scan(&delta)
return NormalizeSiteReceiveRatioDelta(delta), true
}