package handler import ( "encoding/json" "time" "affiliate_dash/internal/pkg/openlog" "affiliate_dash/internal/pkg/response" "affiliate_dash/internal/service" "github.com/gin-gonic/gin" ) // OpenHandler 皮肤源头开放接口 type OpenHandler struct { orderSvc *service.OrderService } func NewOpenHandler(orderSvc *service.OrderService) *OpenHandler { return &OpenHandler{orderSvc: orderSvc} } // QueryOrder GET /api/open/v1/orders/:order_no // 上游输入店铺订单号,查询商品与是否可发货 func (h *OpenHandler) QueryOrder(c *gin.Context) { orderNo := c.Param("order_no") if orderNo == "" { orderNo = c.Query("order_no") } openlog.Info(c, "query_order start order_no=%s", orderNo) data, err := h.orderSvc.QueryOpenOrder(orderNo) if err != nil { openlog.Warn(c, "query_order fail order_no=%s err=%s", orderNo, err.Error()) if err.Error() == "订单不存在" { response.NotFound(c, err.Error()) return } response.BadRequest(c, err.Error()) return } sku, name, game := "", "", "" if data.Product != nil { sku, name, game = data.Product.SKU, data.Product.Name, data.Product.Game } openlog.Info(c, "query_order ok order_no=%s status=%s can_ship=%v reason=%q sku=%s name=%s game=%s buyer=%s amount=%.2f provider_no=%s shipped_at=%v fail_reason=%q", data.OrderNo, data.Status, data.CanShip, data.CannotShipReason, sku, name, game, data.BuyerName, data.Amount, data.ProviderOrderNo, data.ShippedAt, data.ShipFailReason, ) response.OK(c, data) } type shipNotifyReq struct { OrderNo string `json:"order_no" binding:"required"` ShipStatus string `json:"ship_status" binding:"required"` // success/failed/processing ProviderOrderNo string `json:"provider_order_no"` ShippedAt string `json:"shipped_at"` // RFC3339 可选 FailReason string `json:"fail_reason"` } // ShipNotify POST /api/open/v1/orders/ship-notify // 上游发货后推送结果,同步订单状态 func (h *OpenHandler) ShipNotify(c *gin.Context) { var req shipNotifyReq if err := c.ShouldBindJSON(&req); err != nil { openlog.Warn(c, "ship_notify bind_fail err=%v", err) response.BadRequest(c, "参数错误:order_no 与 ship_status 必填") return } raw, _ := json.Marshal(req) openlog.Info(c, "ship_notify start order_no=%s ship_status=%s provider_no=%s shipped_at=%s fail_reason=%q payload=%s", req.OrderNo, req.ShipStatus, req.ProviderOrderNo, req.ShippedAt, req.FailReason, openlog.Truncate(string(raw), 800), ) var shippedAt *time.Time if req.ShippedAt != "" { t, err := time.Parse(time.RFC3339, req.ShippedAt) if err != nil { openlog.Warn(c, "ship_notify bad_shipped_at raw=%s err=%v", req.ShippedAt, err) response.BadRequest(c, "shipped_at 格式错误,请使用 RFC3339,如 2026-07-20T16:00:00+08:00") return } shippedAt = &t } result, err := h.orderSvc.HandleShipNotify(service.ShipNotifyInput{ OrderNo: req.OrderNo, ShipStatus: req.ShipStatus, ProviderOrderNo: req.ProviderOrderNo, ShippedAt: shippedAt, FailReason: req.FailReason, RawPayload: string(raw), }) if err != nil { openlog.Warn(c, "ship_notify fail order_no=%s ship_status=%s err=%s", req.OrderNo, req.ShipStatus, err.Error()) if err.Error() == "订单不存在" { response.NotFound(c, err.Error()) return } response.BadRequest(c, err.Error()) return } openlog.Info(c, "ship_notify ok order_no=%s result_status=%s message=%s", result.OrderNo, result.Status, result.Message) response.OK(c, result) }