纯文件级移动,无行为变更: - 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 声明完全一致(无缺失、无多出、无重复)。
116 lines
3.6 KiB
Go
116 lines
3.6 KiB
Go
package service
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"affiliate_dash/internal/model"
|
|
)
|
|
|
|
const defaultDeliveryBFFBaseURL = "https://www.jxya.top/bff"
|
|
|
|
// 发货提交阶段,持久化在 result_data.provider_order_stage 中,供排障与补偿扫描区分处理。
|
|
const (
|
|
deliveryStageClaimed = "claimed" // 已锁定订单,尚未建 queue
|
|
deliveryStageQueueCreated = "queue_created" // 已在上游建 queue,尚未生成正式订单
|
|
deliveryStageSubmitted = "submitted" // 已在上游创建正式订单
|
|
deliveryStageBindVerify = "bind_verify" // 绑定账号校验失败
|
|
deliveryStageBindMismatch = "bind_mismatch" // 玩家编号与绑定账号不一致
|
|
deliveryStageCreateQueue = "create_queue" // 创建上游 queue 失败
|
|
deliveryStagePatchQueue = "patch_queue" // 补充 queue 账号信息失败
|
|
deliveryStageCreateOrder = "create_upstream" // 创建上游正式订单失败
|
|
|
|
deliverySubmissionStaleTimeout = 10 * time.Minute
|
|
// 第一平台创建正式订单常态约 11 秒,15 秒上限会在偶发变慢时提前断开。
|
|
deliveryUpstreamTimeout = 30 * time.Second
|
|
)
|
|
|
|
// deliverySubmittedUpstream 判断订单是否已成功提交到上游正式订单。
|
|
// 已提交上游的失败订单禁止自动重发,避免重复发货。
|
|
func deliverySubmittedUpstream(order *model.FulfillmentOrder) bool {
|
|
if order == nil {
|
|
return false
|
|
}
|
|
if strings.TrimSpace(order.ProviderOrderNo) != "" {
|
|
return true
|
|
}
|
|
m := resultDataMap(order.ResultData)
|
|
if _, ok := m["delivery"]; ok {
|
|
return true
|
|
}
|
|
if _, ok := m["upstream_order"]; ok { // 兼容历史数据
|
|
return true
|
|
}
|
|
return resultDataString(order.ResultData, "provider_order_stage") == deliveryStageSubmitted
|
|
}
|
|
|
|
type DeliveryService struct {
|
|
fulfillment *FulfillmentService
|
|
bffBaseURL string
|
|
channel string
|
|
linkBaseURL string
|
|
linkSecret string
|
|
linkTTL time.Duration
|
|
httpClient *http.Client
|
|
router *FulfillmentRouter
|
|
}
|
|
|
|
func NewDeliveryService(fulfillment *FulfillmentService, bffBaseURL, channel, linkBaseURL, linkSecret string, linkTTLMinutes int) *DeliveryService {
|
|
bffBaseURL = strings.TrimRight(strings.TrimSpace(bffBaseURL), "/")
|
|
if bffBaseURL == "" {
|
|
bffBaseURL = defaultDeliveryBFFBaseURL
|
|
}
|
|
channel = strings.TrimSpace(channel)
|
|
if channel == "" {
|
|
channel = "dlc"
|
|
}
|
|
linkBaseURL = strings.TrimRight(strings.TrimSpace(linkBaseURL), "/")
|
|
linkSecret = strings.TrimSpace(linkSecret)
|
|
if linkSecret == "" {
|
|
linkSecret = "affiliate-dash-delivery-link-secret"
|
|
}
|
|
// linkTTLMinutes <= 0 表示链接永久有效(0 为默认值)。
|
|
if linkTTLMinutes < 0 {
|
|
linkTTLMinutes = 0
|
|
}
|
|
client := &http.Client{Timeout: deliveryUpstreamTimeout}
|
|
dlc := NewDLCProvider(bffBaseURL, channel, client)
|
|
router := NewFulfillmentRouter(dlc)
|
|
return &DeliveryService{
|
|
fulfillment: fulfillment,
|
|
bffBaseURL: bffBaseURL,
|
|
channel: channel,
|
|
linkBaseURL: linkBaseURL,
|
|
linkSecret: linkSecret,
|
|
linkTTL: time.Duration(linkTTLMinutes) * time.Minute,
|
|
httpClient: client,
|
|
router: router,
|
|
}
|
|
}
|
|
|
|
func (s *DeliveryService) SetHTTPClient(client *http.Client) {
|
|
if client != nil {
|
|
s.httpClient = client
|
|
if dlc, ok := s.router.GetProvider(ProviderDLC).(*DLCProvider); ok && dlc != nil {
|
|
dlc.httpClient = client
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *DeliveryService) SetRouter(router *FulfillmentRouter) {
|
|
if router != nil {
|
|
s.router = router
|
|
}
|
|
}
|
|
|
|
func (s *DeliveryService) RegisterProvider(provider FulfillmentProvider) {
|
|
if s.router == nil {
|
|
s.router = NewFulfillmentRouter(provider)
|
|
} else if provider != nil {
|
|
s.router.providers[provider.Name()] = provider
|
|
}
|
|
}
|
|
|
|
// CancelUpstream 取消订单时同步取消已锁定/已建单的上游履约渠道。
|