纯文件级移动,无行为变更: - 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 声明完全一致(无缺失、无多出、无重复)。
136 lines
3.9 KiB
Go
136 lines
3.9 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"affiliate_dash/internal/model"
|
|
)
|
|
|
|
func (s *DeliveryService) CancelUpstream(order *model.FulfillmentOrder) error {
|
|
if order == nil || s.router == nil {
|
|
return nil
|
|
}
|
|
if name := resultDataString(order.ResultData, "provider"); name != "" {
|
|
if p := s.router.GetProvider(name); p != nil {
|
|
return p.Cancel(context.Background(), order)
|
|
}
|
|
}
|
|
if resultDataString(order.ResultData, "lewan_order_id") != "" {
|
|
if p := s.router.GetProvider(ProviderLewan); p != nil {
|
|
return p.Cancel(context.Background(), order)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SyncDeliveringOrder 主动向上游渠道查询处于 delivering 状态的订单结果,以补充 Webhook 丢失或延迟。
|
|
func (s *DeliveryService) SyncDeliveringOrder(ctx context.Context, order *model.FulfillmentOrder) (bool, error) {
|
|
if order == nil || s.router == nil || order.OrderStatus != model.OrderStatusDelivering {
|
|
return false, nil
|
|
}
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
|
|
providerName := resultDataString(order.ResultData, "provider")
|
|
if providerName == "" && (resultDataString(order.ResultData, "lewan_order_id") != "" || resultDataString(order.ResultData, "lewan_order_no") != "" || strings.HasPrefix(order.ProviderOrderNo, "OMU")) {
|
|
providerName = ProviderLewan
|
|
}
|
|
|
|
providers := make([]FulfillmentProvider, 0, 2)
|
|
if providerName != "" {
|
|
if p := s.router.GetProvider(providerName); p != nil {
|
|
providers = append(providers, p)
|
|
}
|
|
}
|
|
if len(providers) == 0 {
|
|
resolved, _ := s.router.ResolveProviders(order)
|
|
providers = resolved
|
|
}
|
|
|
|
for _, p := range providers {
|
|
res, err := p.SyncStatus(ctx, order)
|
|
if err != nil || res == nil {
|
|
continue
|
|
}
|
|
if res.Status == "success" || res.Status == "failed" {
|
|
input := ShipNotifyInput{
|
|
OrderNo: order.OrderNo,
|
|
ShipStatus: res.Status,
|
|
ProviderOrderNo: res.ProviderOrderNo,
|
|
FailReason: res.FailReason,
|
|
RawPayload: res.RawPayload,
|
|
}
|
|
if res.GameUID != "" {
|
|
input.GameUID = &res.GameUID
|
|
}
|
|
if res.RoleName != "" {
|
|
input.RoleName = &res.RoleName
|
|
}
|
|
if res.RoleArea != "" {
|
|
input.GameChannel = &res.RoleArea
|
|
}
|
|
if _, err := s.fulfillment.HandleShipNotify(input); err != nil {
|
|
return false, err
|
|
}
|
|
return true, nil
|
|
}
|
|
// 如果仍在发货中,且获得了游戏UID/角色名/区服,补充写入 ResultData
|
|
patch := map[string]interface{}{}
|
|
if res.GameUID != "" && resultDataString(order.ResultData, "game_uid") == "" {
|
|
patch["game_uid"] = res.GameUID
|
|
}
|
|
if res.RoleName != "" && resultDataString(order.ResultData, "role_name") == "" {
|
|
patch["role_name"] = res.RoleName
|
|
}
|
|
if res.RoleArea != "" && resultDataString(order.ResultData, "game_channel") == "" {
|
|
patch["game_channel"] = res.RoleArea
|
|
}
|
|
if len(patch) > 0 {
|
|
_ = s.persistOrderResultPatch(order, patch)
|
|
}
|
|
return false, nil
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
// persistOrderResultPatch 合并写入订单 result_data,不改变发货 stage。
|
|
func (s *DeliveryService) persistOrderResultPatch(order *model.FulfillmentOrder, patch map[string]interface{}) error {
|
|
if order == nil || len(patch) == 0 {
|
|
return nil
|
|
}
|
|
resultData := mergeResultData(order.ResultData, patch)
|
|
if err := s.fulfillment.db.Model(&model.FulfillmentOrder{}).
|
|
Where("id = ?", order.ID).
|
|
Update("result_data", resultData).Error; err != nil {
|
|
return err
|
|
}
|
|
order.ResultData = resultData
|
|
return nil
|
|
}
|
|
|
|
func (s *DeliveryService) clearSelectedProvider(order *model.FulfillmentOrder) {
|
|
if order == nil || strings.TrimSpace(order.ResultData) == "" {
|
|
return
|
|
}
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal([]byte(order.ResultData), &raw); err != nil {
|
|
return
|
|
}
|
|
if _, ok := raw["provider"]; !ok {
|
|
return
|
|
}
|
|
delete(raw, "provider")
|
|
b, err := json.Marshal(raw)
|
|
if err != nil {
|
|
return
|
|
}
|
|
resultData := string(b)
|
|
_ = s.fulfillment.db.Model(&model.FulfillmentOrder{}).
|
|
Where("id = ?", order.ID).
|
|
Update("result_data", resultData).Error
|
|
order.ResultData = resultData
|
|
}
|