package service import ( "encoding/json" "errors" "strings" "time" "affiliate_dash/internal/model" "gorm.io/gorm" ) type CreateTestOrderInput struct { MerchantID uint ActorUserID uint SKU string BuyerReference string Note string OrderStatus string } // CreateTestOrder 创建后台联调订单:不扣钱包、不占库存,只用于上游按订单号查询与发货回传。 func (s *FulfillmentService) CreateTestOrder(in CreateTestOrderInput) (*model.FulfillmentOrder, error) { in.SKU = strings.TrimSpace(in.SKU) in.BuyerReference = strings.TrimSpace(in.BuyerReference) in.Note = strings.TrimSpace(in.Note) if in.MerchantID == 0 { return nil, errors.New("无效的商户") } if in.SKU == "" { return nil, errors.New("sku 不能为空") } if in.BuyerReference == "" { in.BuyerReference = "测试买家" } if len(in.BuyerReference) > 128 { return nil, errors.New("买家标识最长 128 位") } if len(in.Note) > 512 { return nil, errors.New("备注最长 512 位") } if in.OrderStatus == "" { in.OrderStatus = model.OrderStatusPaid } switch in.OrderStatus { case model.OrderStatusPaid, model.OrderStatusShipFailed, model.OrderStatusCancelled: default: return nil, errors.New("测试订单仅支持已支付待发货、发货失败或已取消状态") } requestData := map[string]interface{}{ "source": "merchant_test_order", } if in.Note != "" { requestData["note"] = in.Note } rawRequestData, err := json.Marshal(requestData) if err != nil { return nil, errors.New("订单请求数据无法序列化") } var out model.FulfillmentOrder err = s.db.Transaction(func(tx *gorm.DB) error { var merchant model.Merchant if err := tx.Where("id = ? AND status = ?", in.MerchantID, model.MerchantStatusActive).First(&merchant).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("商户不存在或已禁用") } return err } var product model.MerchantProduct if err := tx.Preload("Product"). Where("merchant_id = ? AND sku = ? AND status = ?", in.MerchantID, in.SKU, model.ProductStatusActive). First(&product).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("商品不存在或已下架") } return err } if product.Product == nil || product.Product.Status != model.ProductStatusActive { return errors.New("商品目录已下架") } orderNo := newTestFulfillmentOrderNo() order := &model.FulfillmentOrder{ MerchantID: in.MerchantID, OrderNo: orderNo, ClientOrderNo: "TEST-" + orderNo, MerchantProductID: product.ID, ProductSKU: product.SKU, ProductName: fallbackName(product.DisplayName, product.Product.Name), Quantity: 1, BaseAmount: 0, FeeType: merchant.FeeType, FeeRateBP: merchant.FeeRateBP, FeeFixedAmount: merchant.FeeFixedAmount, ServiceFeeAmount: 0, Amount: 0, Currency: product.Currency, OrderStatus: in.OrderStatus, OrderSource: model.OrderSourceTest, BuyerReference: in.BuyerReference, RequestData: string(rawRequestData), } if in.OrderStatus == model.OrderStatusShipFailed { order.FailureReason = fallbackName(in.Note, "联调测试订单初始化为发货失败,可重新发货") } if in.OrderStatus == model.OrderStatusCancelled { now := time.Now() order.CancelledAt = &now } if err := tx.Create(order).Error; err != nil { return err } canShip, _ := CanFulfill(order) if err := writeAudit(tx, &in.MerchantID, &in.ActorUserID, nil, "merchant_test_order.create", "fulfillment_order", order.OrderNo, map[string]interface{}{ "sku": in.SKU, "order_status": in.OrderStatus, "can_ship": canShip, }); err != nil { return err } out = *order out.MerchantProduct = &product return nil }) if err != nil { return nil, err } return &out, nil }