Files
affiliate_dash/backend/internal/service/fulfillment_state.go
T
2026-07-31 17:02:19 +08:00

149 lines
4.3 KiB
Go

package service
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"time"
"affiliate_dash/internal/model"
)
type fulfillmentTransitionKind string
const (
fulfillmentTransitionUpdate fulfillmentTransitionKind = "update"
fulfillmentTransitionShipNotify fulfillmentTransitionKind = "ship_notify"
fulfillmentTransitionTimeout fulfillmentTransitionKind = "timeout"
)
type orderRequestFingerprintPayload struct {
ClientOrderNo string `json:"client_order_no"`
SKU string `json:"sku"`
Quantity int64 `json:"quantity"`
BuyerReference string `json:"buyer_reference"`
RequestData string `json:"request_data"`
}
func orderRequestFingerprint(in CreateFulfillmentOrderInput, requestData string) string {
raw, _ := json.Marshal(orderRequestFingerprintPayload{
ClientOrderNo: in.ClientOrderNo,
SKU: in.SKU,
Quantity: in.Quantity,
BuyerReference: in.BuyerReference,
RequestData: requestData,
})
sum := sha256.Sum256(raw)
return hex.EncodeToString(sum[:])
}
func storedOrderRequestFingerprint(order *model.FulfillmentOrder) string {
if order == nil {
return ""
}
if order.RequestFingerprint != "" {
return order.RequestFingerprint
}
return orderRequestFingerprint(CreateFulfillmentOrderInput{
ClientOrderNo: order.ClientOrderNo,
SKU: order.ProductSKU,
Quantity: order.Quantity,
BuyerReference: order.BuyerReference,
}, order.RequestData)
}
func ensureSameIdempotentOrder(existing *model.FulfillmentOrder, fingerprint string) error {
if existing == nil {
return errors.New("订单不存在")
}
if storedOrderRequestFingerprint(existing) != fingerprint {
return errors.New("client_order_no 已存在,但本次请求参数与原订单不一致")
}
return nil
}
func normalizeOrderStatus(order *model.FulfillmentOrder) string {
if order == nil {
return ""
}
if order.OrderStatus != "" {
return order.OrderStatus
}
return model.OrderStatusPaid
}
func validateOrderStatusTransition(order *model.FulfillmentOrder, next string, kind fulfillmentTransitionKind) error {
if order == nil {
return errors.New("订单不存在")
}
current := normalizeOrderStatus(order)
if current == next {
return nil
}
switch current {
case model.OrderStatusPending:
if next == model.OrderStatusPaid || next == model.OrderStatusCancelled {
return nil
}
return errors.New("订单未支付,不能履约")
case model.OrderStatusCancelled:
return errors.New("订单已取消,不能更新状态")
case model.OrderStatusDelivered:
return errors.New("订单已履约成功,不能回退状态")
}
switch next {
case model.OrderStatusDelivering:
if current == model.OrderStatusPaid || current == model.OrderStatusShipFailed {
return nil
}
case model.OrderStatusDelivered:
if current == model.OrderStatusPaid ||
current == model.OrderStatusShipFailed ||
current == model.OrderStatusDelivering {
return nil
}
case model.OrderStatusShipFailed:
if kind == fulfillmentTransitionTimeout && current != model.OrderStatusDelivering {
return errors.New("只有履约中的订单可以标记超时")
}
if current == model.OrderStatusPaid ||
current == model.OrderStatusShipFailed ||
current == model.OrderStatusDelivering {
return nil
}
case model.OrderStatusCancelled:
if current == model.OrderStatusPaid || current == model.OrderStatusShipFailed {
return nil
}
}
return errors.New("订单当前状态不允许该状态变更")
}
func canCancelOrder(order *model.FulfillmentOrder) error {
if order == nil {
return errors.New("订单不存在")
}
status := normalizeOrderStatus(order)
if status == model.OrderStatusCancelled {
return nil
}
switch status {
case model.OrderStatusPaid, model.OrderStatusShipFailed:
return nil
case model.OrderStatusPending:
return errors.New("订单未支付,不能取消")
case model.OrderStatusDelivering, model.OrderStatusDelivered:
return errors.New("订单已进入履约流程,不能取消")
default:
return errors.New("订单当前状态不能取消")
}
}
func processingTimedOut(order *model.FulfillmentOrder, timeout time.Duration, now time.Time) bool {
if order == nil || timeout <= 0 {
return false
}
return normalizeOrderStatus(order) == model.OrderStatusDelivering && order.UpdatedAt.Before(now.Add(-timeout))
}