package service import ( "errors" "time" "affiliate_dash/internal/model" "gorm.io/gorm" "gorm.io/gorm/clause" ) type FulfillmentUpdateInput struct { MerchantID uint APIClientID uint OrderNo string Status string ProviderOrderNo string FailureReason string ResultData interface{} } func (s *FulfillmentService) UpdateFulfillment(in FulfillmentUpdateInput) (*model.FulfillmentOrder, error) { switch in.Status { case model.OrderStatusDelivering, model.OrderStatusDelivered, model.OrderStatusShipFailed: default: return nil, errors.New("无效的订单状态") } nextOrderStatus := in.Status var resultData string hasResultData := in.ResultData != nil if in.ResultData != nil { encoded, err := encodeFulfillmentResultData(in.ResultData) if err != nil { return nil, errors.New("发货结果无法序列化") } resultData = encoded } var out model.FulfillmentOrder err := s.db.Transaction(func(tx *gorm.DB) error { var order model.FulfillmentOrder if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}). Where("merchant_id = ? AND order_no = ?", in.MerchantID, in.OrderNo). First(&order).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("订单不存在") } return err } if normalizeOrderStatus(&order) == model.OrderStatusDelivered && nextOrderStatus == model.OrderStatusDelivered { out = order return nil } if err := validateOrderStatusTransition(&order, nextOrderStatus, fulfillmentTransitionUpdate); err != nil { return err } now := time.Now() updates := map[string]interface{}{"order_status": nextOrderStatus} if hasResultData { updates["result_data"] = resultData } if in.ProviderOrderNo != "" { updates["provider_order_no"] = in.ProviderOrderNo } switch nextOrderStatus { case model.OrderStatusDelivered: updates["delivered_at"] = now updates["failure_reason"] = "" case model.OrderStatusShipFailed: updates["failure_reason"] = in.FailureReason } if err := tx.Model(&order).Updates(updates).Error; err != nil { return err } if err := tx.First(&out, order.ID).Error; err != nil { return err } if err := writeAudit(tx, &in.MerchantID, nil, &in.APIClientID, "fulfillment.update", "fulfillment_order", order.OrderNo, map[string]string{"status": nextOrderStatus}); err != nil { return err } if s.callbacks != nil { if err := s.callbacks.Enqueue(tx, in.MerchantID, "order.shipping.updated", orderCallbackData(&out)); err != nil { return err } } return nil }) if err != nil { return nil, err } return &out, nil }