Files
affiliate_dash/backend/internal/service/delivery_query.go
T
yml2213 24fa6a97a0 refactor(delivery): 按职责拆分 delivery.go(1162 → 最大 249 行)
纯文件级移动,无行为变更:
- delivery.go            常量、DeliveryService 结构、构造与依赖注入
- delivery_types.go      对外 DTO 与 deliveryHTTPError
- delivery_provider.go   渠道取消/同步与 result_data 维护
- delivery_query.go      订单查询与发货状态构建
- delivery_bind.go       绑定与绑定结果查询
- delivery_submit.go     提交发货与提交阶段状态机
- deliveryGoodID 并入 delivery_helpers.go,链接管理并入 delivery_link.go

校验:拆分前后 55 个 func/type/const 声明完全一致(无缺失、无多出、无重复)。
2026-10-06 19:43:05 +08:00

248 lines
7.7 KiB
Go

package service
import (
"context"
"errors"
"net/http"
"strings"
"affiliate_dash/internal/model"
)
func (s *DeliveryService) GetOrder(orderNo string, auth DeliveryLinkAuth) (*DeliveryOrderInfo, error) {
info, _, _, err := s.prepareOrder(orderNo, false, &auth)
return info, err
}
func (s *DeliveryService) GetMerchantOrder(merchantID uint, orderNo string) (*DeliveryOrderInfo, error) {
openOrder, order, goodID, err := s.loadMerchantOrder(merchantID, orderNo)
if err != nil {
return nil, err
}
info, _, _, err := s.buildDeliveryState(openOrder, order, goodID, false)
return info, err
}
func (s *DeliveryService) loadLinkedOrder(orderNo string, auth *DeliveryLinkAuth) (*OpenOrderQuery, *model.FulfillmentOrder, string, error) {
openOrder, err := s.fulfillment.QueryOpenOrder(orderNo)
if err != nil {
return nil, nil, "", err
}
order, err := s.fulfillment.GetByOrderNo(orderNo)
if err != nil {
return nil, nil, "", err
}
if auth != nil {
if err := s.authorizeDeliveryLink(order, *auth); err != nil {
return nil, nil, "", err
}
}
goodID := ""
if openOrder.Product != nil {
goodID = deliveryGoodID(s.channel, openOrder.Product.SKU)
}
return openOrder, order, goodID, nil
}
func (s *DeliveryService) loadMerchantOrder(merchantID uint, orderNo string) (*OpenOrderQuery, *model.FulfillmentOrder, string, error) {
if merchantID == 0 {
return nil, nil, "", errors.New("无效的商户")
}
openOrder, err := s.fulfillment.QueryOpenOrder(orderNo)
if err != nil {
return nil, nil, "", err
}
order, err := s.fulfillment.GetOrder(merchantID, orderNo)
if err != nil {
return nil, nil, "", err
}
if order.OrderStatus == model.OrderStatusDelivering {
if synced, _ := s.SyncDeliveringOrder(context.Background(), order); synced {
openOrder, _ = s.fulfillment.QueryOpenOrder(orderNo)
order, _ = s.fulfillment.GetOrder(merchantID, orderNo)
}
}
goodID := ""
if openOrder != nil && openOrder.Product != nil {
goodID = deliveryGoodID(s.channel, openOrder.Product.SKU)
}
return openOrder, order, goodID, nil
}
func (s *DeliveryService) buildDeliveryState(openOrder *OpenOrderQuery, order *model.FulfillmentOrder, goodID string, requireCanShip bool) (*DeliveryOrderInfo, *model.FulfillmentOrder, string, error) {
if openOrder == nil || order == nil {
return nil, nil, "", errors.New("订单不存在")
}
canShip, reason := CanFulfill(order)
if !openOrder.CanShip {
reason = openOrder.CannotShipReason
canShip = false
}
if !canShip && reason == "" {
reason = "订单暂不可发货"
}
if openOrder.Product == nil || openOrder.Product.SKU == "" {
canShip = false
reason = "订单缺少商品 SKU"
}
var (
deliveryProd *DeliveryProduct
goodData map[string]interface{}
)
providers, _ := s.router.ResolveProviders(order)
if len(providers) > 0 {
locked := resultDataString(order.ResultData, "provider") != ""
matchedState, lastReason := s.tryPrepareProviders(order, openOrder, providers)
// 已锁定渠道不可发时,清除锁定并按完整优先级重新选择
if matchedState == nil && locked {
s.clearSelectedProvider(order)
providers, _ = s.router.ResolveProviders(order)
matchedState, lastReason = s.tryPrepareProviders(order, openOrder, providers)
}
if matchedState != nil {
deliveryProd = matchedState.Product
goodData = matchedState.Good
if matchedState.Provider != "" {
_ = s.persistOrderResultPatch(order, map[string]interface{}{
"provider": matchedState.Provider,
})
}
} else {
canShip = false
if reason == "" || reason == "订单暂不可发货" {
reason = lastReason
if reason == "" {
reason = "未找到适用的履约渠道配置"
}
}
}
} else if goodID != "" {
goodData, _ = s.goodsDetail(goodID)
}
if deliveryProd == nil && openOrder.Product != nil {
deliveryProd = buildDeliveryProduct(openOrder.Product, goodData)
}
if requireCanShip && !canShip {
return nil, nil, "", newDeliveryHTTPError(http.StatusBadRequest, reason)
}
providerOrderNo := strings.TrimSpace(openOrder.ProviderOrderNo)
if providerOrderNo == "" {
providerOrderNo = strings.TrimSpace(order.ProviderOrderNo)
}
if providerOrderNo == "" {
providerOrderNo = resultDataString(order.ResultData, "lewan_order_no")
}
if providerOrderNo == "" {
providerOrderNo = resultDataString(order.ResultData, "provider_order_no")
}
providerName := resultDataString(order.ResultData, "provider")
if providerName == "" {
if strings.TrimSpace(order.ProviderOrderNo) != "" || resultDataString(order.ResultData, "lewan_order_id") != "" {
providerName = "lewan"
}
}
roleName := openOrder.RoleName
if roleName == "" {
roleName = resultDataString(order.ResultData, "role_name")
}
gameChannel := openOrder.GameChannel
if gameChannel == "" {
gameChannel = resultDataString(order.ResultData, "game_channel")
}
// 若角色名或区服为空,尝试从关联的 rock_tokens 表反查并自动回填
if (roleName == "" || gameChannel == "") && s.fulfillment != nil && s.fulfillment.db != nil {
var rockToken model.RockToken
if err := s.fulfillment.db.Where("assigned_order_no = ?", order.OrderNo).First(&rockToken).Error; err == nil {
patches := map[string]interface{}{}
if roleName == "" && rockToken.ActualRoleName != "" {
roleName = rockToken.ActualRoleName
patches["role_name"] = roleName
}
if gameChannel == "" && rockToken.ActualChannel != "" {
gameChannel = rockToken.ActualChannel
patches["game_channel"] = gameChannel
}
if len(patches) > 0 {
_ = s.persistOrderResultPatch(order, patches)
}
}
}
info := &DeliveryOrderInfo{
OrderNo: openOrder.OrderNo,
Status: openOrder.Status,
CanShip: canShip,
CannotShipReason: reason,
Product: deliveryProd,
BuyerName: openOrder.BuyerName,
Amount: openOrder.Amount,
ProviderOrderNo: providerOrderNo,
ProviderName: providerName,
CreatedAt: openOrder.CreatedAt,
ShippedAt: openOrder.ShippedAt,
ShipFailReason: openOrder.ShipFailReason,
GameChannel: gameChannel,
GameUID: openOrder.GameUID,
RoleName: roleName,
PayScore: openOrder.PayScore,
Data: requestDataMap(order.RequestData),
Good: goodData,
}
return info, order, goodID, nil
}
// tryPrepareProviders 按优先级尝试 Prepare,返回第一个 CanShip 的渠道状态。
func (s *DeliveryService) tryPrepareProviders(order *model.FulfillmentOrder, openOrder *OpenOrderQuery, providers []FulfillmentProvider) (*DeliveryOrderState, string) {
lastReason := ""
for _, p := range providers {
state, err := p.PrepareDelivery(context.Background(), order, openOrder)
if err != nil || state == nil {
continue
}
if state.Provider == "" {
state.Provider = p.Name()
}
if state.CanShip {
return state, ""
}
if state.CannotShipReason != "" {
lastReason = state.CannotShipReason
}
}
return nil, lastReason
}
func (s *DeliveryService) prepareOrder(orderNo string, requireCanShip bool, auth *DeliveryLinkAuth) (*DeliveryOrderInfo, *model.FulfillmentOrder, string, error) {
orderNo = strings.TrimSpace(orderNo)
if orderNo == "" {
return nil, nil, "", errors.New("订单号不能为空")
}
openOrder, err := s.fulfillment.QueryOpenOrder(orderNo)
if err != nil {
return nil, nil, "", err
}
order, err := s.fulfillment.GetByOrderNo(orderNo)
if err != nil {
return nil, nil, "", err
}
if auth != nil {
if err := s.authorizeDeliveryLink(order, *auth); err != nil {
return nil, nil, "", err
}
}
if order.OrderStatus == model.OrderStatusDelivering {
if synced, _ := s.SyncDeliveringOrder(context.Background(), order); synced {
openOrder, _ = s.fulfillment.QueryOpenOrder(orderNo)
order, _ = s.fulfillment.GetByOrderNo(orderNo)
}
}
return s.buildDeliveryState(openOrder, order, "", requireCanShip)
}