feat: add manual fulfillment order creation
This commit is contained in:
@@ -26,11 +26,13 @@ func NewFulfillmentService(db *gorm.DB, callbacks *CallbackService) *Fulfillment
|
||||
type CreateFulfillmentOrderInput struct {
|
||||
MerchantID uint
|
||||
APIClientID uint
|
||||
ActorUserID uint
|
||||
ClientOrderNo string
|
||||
SKU string
|
||||
Quantity int64
|
||||
BuyerReference string
|
||||
RequestData interface{}
|
||||
OrderSource string
|
||||
}
|
||||
|
||||
type CreateFulfillmentOrderResult struct {
|
||||
@@ -47,11 +49,35 @@ type CreateTestOrderInput struct {
|
||||
OrderStatus string
|
||||
}
|
||||
|
||||
// CreateManualOrderInput 是商户后台创建真实订单的输入。其账务、库存与回调规则与开放 API 下单一致。
|
||||
type CreateManualOrderInput struct {
|
||||
MerchantID uint
|
||||
ActorUserID uint
|
||||
ClientOrderNo string
|
||||
SKU string
|
||||
Quantity int64
|
||||
BuyerReference string
|
||||
RequestData interface{}
|
||||
}
|
||||
|
||||
func (s *FulfillmentService) CreateManualOrder(in CreateManualOrderInput) (*CreateFulfillmentOrderResult, error) {
|
||||
return s.CreateOrder(CreateFulfillmentOrderInput{
|
||||
MerchantID: in.MerchantID,
|
||||
ActorUserID: in.ActorUserID,
|
||||
ClientOrderNo: in.ClientOrderNo,
|
||||
SKU: in.SKU,
|
||||
Quantity: in.Quantity,
|
||||
BuyerReference: in.BuyerReference,
|
||||
RequestData: in.RequestData,
|
||||
OrderSource: model.OrderSourceManual,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*CreateFulfillmentOrderResult, error) {
|
||||
in.ClientOrderNo = strings.TrimSpace(in.ClientOrderNo)
|
||||
in.SKU = strings.TrimSpace(in.SKU)
|
||||
if in.MerchantID == 0 || in.APIClientID == 0 {
|
||||
return nil, errors.New("无效的商户或 API 客户端")
|
||||
if in.MerchantID == 0 || (in.APIClientID == 0 && in.ActorUserID == 0) {
|
||||
return nil, errors.New("无效的商户或下单身份")
|
||||
}
|
||||
if in.ClientOrderNo == "" || len(in.ClientOrderNo) > 96 {
|
||||
return nil, errors.New("client_order_no 不能为空且最长 96 位")
|
||||
@@ -65,6 +91,15 @@ func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*Creat
|
||||
if in.Quantity < 1 {
|
||||
return nil, errors.New("quantity 必须大于零")
|
||||
}
|
||||
orderSource := strings.TrimSpace(in.OrderSource)
|
||||
if orderSource == "" {
|
||||
orderSource = model.OrderSourceAPI
|
||||
}
|
||||
switch orderSource {
|
||||
case model.OrderSourceAPI, model.OrderSourceManual:
|
||||
default:
|
||||
return nil, errors.New("无效的订单来源")
|
||||
}
|
||||
requestData := ""
|
||||
if in.RequestData != nil {
|
||||
raw, err := json.Marshal(in.RequestData)
|
||||
@@ -155,6 +190,7 @@ func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*Creat
|
||||
Amount: totalAmount,
|
||||
Currency: product.Currency,
|
||||
OrderStatus: model.OrderStatusPaid,
|
||||
OrderSource: orderSource,
|
||||
BuyerReference: in.BuyerReference,
|
||||
RequestFingerprint: fingerprint,
|
||||
RequestData: requestData,
|
||||
@@ -163,6 +199,10 @@ func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*Creat
|
||||
return err
|
||||
}
|
||||
idempotencyKey := in.ClientOrderNo
|
||||
ledgerNote := "开放接口下单扣款(含平台手续费)"
|
||||
if orderSource == model.OrderSourceManual {
|
||||
ledgerNote = "商户后台手动下单扣款(含平台手续费)"
|
||||
}
|
||||
if err := tx.Create(&model.WalletLedgerEntry{
|
||||
MerchantID: in.MerchantID,
|
||||
WalletAccountID: wallet.ID,
|
||||
@@ -173,7 +213,7 @@ func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*Creat
|
||||
ReferenceType: "fulfillment_order",
|
||||
ReferenceNo: order.OrderNo,
|
||||
IdempotencyKey: &idempotencyKey,
|
||||
Note: "开放接口下单扣款(含平台手续费)",
|
||||
Note: ledgerNote,
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -183,7 +223,11 @@ func (s *FulfillmentService) CreateOrder(in CreateFulfillmentOrderInput) (*Creat
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := writeAudit(tx, &in.MerchantID, nil, &in.APIClientID, "open_order.create", "fulfillment_order", order.OrderNo, map[string]interface{}{"client_order_no": in.ClientOrderNo, "sku": in.SKU}); err != nil {
|
||||
action := "open_order.create"
|
||||
if orderSource == model.OrderSourceManual {
|
||||
action = "merchant_order.manual_create"
|
||||
}
|
||||
if err := writeAudit(tx, &in.MerchantID, optionalUint(in.ActorUserID), optionalUint(in.APIClientID), action, "fulfillment_order", order.OrderNo, map[string]interface{}{"client_order_no": in.ClientOrderNo, "sku": in.SKU, "source": orderSource}); err != nil {
|
||||
return err
|
||||
}
|
||||
if s.callbacks != nil {
|
||||
@@ -289,6 +333,7 @@ func (s *FulfillmentService) CreateTestOrder(in CreateTestOrderInput) (*model.Fu
|
||||
Amount: 0,
|
||||
Currency: product.Currency,
|
||||
OrderStatus: in.OrderStatus,
|
||||
OrderSource: model.OrderSourceTest,
|
||||
BuyerReference: in.BuyerReference,
|
||||
RequestData: string(rawRequestData),
|
||||
}
|
||||
@@ -511,6 +556,7 @@ func orderCallbackData(order *model.FulfillmentOrder) map[string]interface{} {
|
||||
"amount": order.Amount,
|
||||
"currency": order.Currency,
|
||||
"order_status": normalizeOrderStatus(order),
|
||||
"order_source": order.OrderSource,
|
||||
"can_ship": canShip,
|
||||
"cannot_ship_reason": cannotShipReason,
|
||||
"provider_order_no": order.ProviderOrderNo,
|
||||
|
||||
Reference in New Issue
Block a user