fix(distribution): 修复收号站订单详情权限、专属支付通道路由、大盘统计与仲裁积分隔离
- 修复 FindOrder 在收号站模式(two_party_distributor_receive / three_party)下的 403 权限判定,放行参与方站点成员并精准计算收益 - 串联 distribution_site_payment_channels 至 payment.Start 核心支付发起流程,分销订单优先使用绑定的专属商户通道 - 修复数据大盘 GetDashboardAnalytics 趋势中 ReceivedCount 恒为 0 的问题,并对齐今日订单与 GMV 统计 - 修复 dispute/arbitration.go 仲裁完成时向分销租客发放成长积分的泄漏风险 - 提现管理新增 distribution_site_name/distribution_site_code 字段并在后台列表与详情弹窗中区分展示分销站 - GetPublicSiteInfo 增加 X-Distribution-Site-Code 请求头兜底支持
This commit is contained in:
@@ -662,40 +662,101 @@ func (r *Repository) FindOrder(ctx context.Context, adminID, id uint64) (*Distri
|
||||
if item.OrderID == 0 {
|
||||
return nil, ErrOrderNotFound
|
||||
}
|
||||
if err := r.ensureSiteAccess(ctx, adminID, item.SiteID); err != nil {
|
||||
var parties []model.DistributionOrderParty
|
||||
if err := r.db.WithContext(ctx).Where("order_id = ?", item.OrderID).Find(&parties).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var parties []model.DistributionOrderParty
|
||||
if err := r.db.WithContext(ctx).Where("order_id = ? AND (site_id = ? OR party_id = ?)", item.OrderID, item.SiteID, item.SiteID).Find(&parties).Error; err == nil {
|
||||
var totalEarning int64
|
||||
var markupCent int64
|
||||
var splitCent int64
|
||||
var roles []string
|
||||
for _, p := range parties {
|
||||
if p.PartyType != PartyTypeSite {
|
||||
continue
|
||||
var siteSet map[uint64]struct{}
|
||||
if adminID != 0 {
|
||||
global, err := r.hasGlobalDistributionAccessWithDB(ctx, r.db, adminID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !global {
|
||||
var adminSiteIDs []uint64
|
||||
if err := r.db.WithContext(ctx).Model(&model.DistributionSiteMember{}).
|
||||
Where("admin_user_id = ? AND status = 'active'", adminID).
|
||||
Pluck("site_id", &adminSiteIDs).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
totalEarning += p.IncomeAmountCent
|
||||
if p.PartyRole == "distributor_sell" || p.PartyRole == "distributor_b" {
|
||||
roles = append(roles, "sell")
|
||||
// 退款压缩加价后收入可能小于货架加价:加价部分取两者较小值,
|
||||
// 避免展示负的提价分成。
|
||||
markup := item.ShelfMarkupCent
|
||||
if p.IncomeAmountCent < markup {
|
||||
markup = p.IncomeAmountCent
|
||||
siteSet = make(map[uint64]struct{}, len(adminSiteIDs))
|
||||
for _, sid := range adminSiteIDs {
|
||||
siteSet[sid] = struct{}{}
|
||||
}
|
||||
hasAccess := false
|
||||
if item.SiteID > 0 {
|
||||
if _, ok := siteSet[item.SiteID]; ok {
|
||||
hasAccess = true
|
||||
}
|
||||
markupCent += markup
|
||||
splitCent += p.IncomeAmountCent - markup
|
||||
} else if p.PartyRole == "distributor_receive" || p.PartyRole == "distributor_a" {
|
||||
roles = append(roles, "receive")
|
||||
splitCent += p.IncomeAmountCent
|
||||
}
|
||||
if !hasAccess {
|
||||
for _, p := range parties {
|
||||
if p.PartyType == PartyTypeSite {
|
||||
if p.SiteID > 0 {
|
||||
if _, ok := siteSet[p.SiteID]; ok {
|
||||
hasAccess = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if p.PartyID > 0 {
|
||||
if _, ok := siteSet[p.PartyID]; ok {
|
||||
hasAccess = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasAccess {
|
||||
return nil, ErrSiteAccessDenied
|
||||
}
|
||||
}
|
||||
item.DistributorEarningCent = totalEarning
|
||||
item.DistributorMarkupCent = markupCent
|
||||
item.DistributorSplitCent = splitCent
|
||||
item.DistributorRole = strings.Join(roles, ",")
|
||||
}
|
||||
|
||||
var totalEarning int64
|
||||
var markupCent int64
|
||||
var splitCent int64
|
||||
var roles []string
|
||||
for _, p := range parties {
|
||||
if p.PartyType != PartyTypeSite {
|
||||
continue
|
||||
}
|
||||
if len(siteSet) > 0 {
|
||||
match := false
|
||||
if p.SiteID > 0 {
|
||||
if _, ok := siteSet[p.SiteID]; ok {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
if p.PartyID > 0 {
|
||||
if _, ok := siteSet[p.PartyID]; ok {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
}
|
||||
totalEarning += p.IncomeAmountCent
|
||||
if p.PartyRole == "distributor_sell" || p.PartyRole == "distributor_b" {
|
||||
roles = append(roles, "sell")
|
||||
// 退款压缩加价后收入可能小于货架加价:加价部分取两者较小值,
|
||||
// 避免展示负的提价分成。
|
||||
markup := item.ShelfMarkupCent
|
||||
if p.IncomeAmountCent < markup {
|
||||
markup = p.IncomeAmountCent
|
||||
}
|
||||
markupCent += markup
|
||||
splitCent += p.IncomeAmountCent - markup
|
||||
} else if p.PartyRole == "distributor_receive" || p.PartyRole == "distributor_a" {
|
||||
roles = append(roles, "receive")
|
||||
splitCent += p.IncomeAmountCent
|
||||
}
|
||||
}
|
||||
item.DistributorEarningCent = totalEarning
|
||||
item.DistributorMarkupCent = markupCent
|
||||
item.DistributorSplitCent = splitCent
|
||||
item.DistributorRole = strings.Join(roles, ",")
|
||||
return &item, nil
|
||||
}
|
||||
|
||||
@@ -2350,13 +2411,14 @@ func (r *Repository) GetDashboardAnalytics(ctx context.Context, adminID, siteID
|
||||
Where("distribution_site_id = ? AND status = 'published' AND review_status = 'approved'", siteID).Count(&activeListings).Error
|
||||
|
||||
var todayOrders int64
|
||||
_ = r.db.WithContext(ctx).Model(&model.RentalOrder{}).
|
||||
Where("distribution_site_id = ? AND created_at >= ?", siteID, todayStr+" 00:00:00").Count(&todayOrders).Error
|
||||
_ = r.db.WithContext(ctx).Table("rental_orders ro").
|
||||
Where("(ro.distribution_site_id = ? OR EXISTS (SELECT 1 FROM distribution_order_parties p WHERE p.order_id = ro.id AND (p.site_id = ? OR p.party_id = ?))) AND ro.created_at >= ?", siteID, siteID, siteID, todayStr+" 00:00:00").
|
||||
Count(&todayOrders).Error
|
||||
|
||||
var todayGMV int64
|
||||
_ = r.db.WithContext(ctx).Table("rental_orders ro").
|
||||
Joins("JOIN distribution_order_financials f ON f.order_id = ro.id").
|
||||
Where("ro.distribution_site_id = ? AND ro.created_at >= ?", siteID, todayStr+" 00:00:00").
|
||||
Where("(ro.distribution_site_id = ? OR EXISTS (SELECT 1 FROM distribution_order_parties p WHERE p.order_id = ro.id AND (p.site_id = ? OR p.party_id = ?))) AND ro.created_at >= ?", siteID, siteID, siteID, todayStr+" 00:00:00").
|
||||
Select("COALESCE(SUM(f.gross_paid_amount_cent), 0)").Scan(&todayGMV).Error
|
||||
|
||||
var todayProfit int64
|
||||
@@ -2374,11 +2436,9 @@ func (r *Repository) GetDashboardAnalytics(ctx context.Context, adminID, siteID
|
||||
|
||||
trendDays := make([]DistributionTrendPoint, 0, 7)
|
||||
type trendRow struct {
|
||||
DateStr string `gorm:"column:date_str"`
|
||||
Received int64 `gorm:"column:received"`
|
||||
Orders int64 `gorm:"column:orders"`
|
||||
GMV int64 `gorm:"column:gmv"`
|
||||
Profit int64 `gorm:"column:profit"`
|
||||
DateStr string `gorm:"column:date_str"`
|
||||
Orders int64 `gorm:"column:orders"`
|
||||
GMV int64 `gorm:"column:gmv"`
|
||||
}
|
||||
var tRows []trendRow
|
||||
startDate := time.Now().AddDate(0, 0, -6).Format("2006-01-02")
|
||||
@@ -2393,6 +2453,22 @@ func (r *Repository) GetDashboardAnalytics(ctx context.Context, adminID, siteID
|
||||
Order("date_str ASC").
|
||||
Scan(&tRows).Error
|
||||
|
||||
type receivedRow struct {
|
||||
DateStr string `gorm:"column:date_str"`
|
||||
Received int64 `gorm:"column:received"`
|
||||
}
|
||||
var rRows []receivedRow
|
||||
dateFormatListingExpr := "DATE_FORMAT(created_at, '%Y-%m-%d')"
|
||||
_ = r.db.WithContext(ctx).Model(&model.RentalListing{}).
|
||||
Where("distribution_site_id = ? AND created_at >= ?", siteID, startDate+" 00:00:00").
|
||||
Select(fmt.Sprintf("%s AS date_str, COUNT(id) AS received", dateFormatListingExpr)).
|
||||
Group(dateFormatListingExpr).
|
||||
Scan(&rRows).Error
|
||||
rRowMap := make(map[string]int64, len(rRows))
|
||||
for _, rr := range rRows {
|
||||
rRowMap[rr.DateStr] = rr.Received
|
||||
}
|
||||
|
||||
type profitRow struct {
|
||||
DateStr string `gorm:"column:date_str"`
|
||||
Profit int64 `gorm:"column:profit"`
|
||||
@@ -2417,7 +2493,7 @@ func (r *Repository) GetDashboardAnalytics(ctx context.Context, adminID, siteID
|
||||
tr := tRowMap[dStr]
|
||||
trendDays = append(trendDays, DistributionTrendPoint{
|
||||
Date: dStr,
|
||||
ReceivedCount: tr.Received,
|
||||
ReceivedCount: rRowMap[dStr],
|
||||
OrderCount: tr.Orders,
|
||||
GMVCent: tr.GMV,
|
||||
ProfitCent: pRowMap[dStr],
|
||||
|
||||
Reference in New Issue
Block a user