Files
affiliate_dash/backend/internal/service/delivery.go
T

129 lines
4.1 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 deliveryPendingUpstream(order) {
return true
}
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
}
// deliveryPendingUpstream 表示 Rock 已受理兑换,正在等待上游确认。
// pending 不等于“提交中断”,订单超时扫描必须跳过。
func deliveryPendingUpstream(order *model.FulfillmentOrder) bool {
if order == nil {
return false
}
stage := resultDataString(order.ResultData, "provider_order_stage")
return stage == "redeem_pending" || boolFromMap(resultDataMap(order.ResultData), "rock_redeem_pending")
}
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 取消订单时同步取消已锁定/已建单的上游履约渠道。