From 6457ffa6f9cf78b382b5e2b640b8101d61b71c7a Mon Sep 17 00:00:00 2001 From: huang Date: Tue, 31 Mar 2026 18:12:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E6=BF=80=E6=B4=BB=E5=A5=97=E9=A4=90=E5=90=8E=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E5=81=9C=E6=9C=BA=E5=8D=A1=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=A4=8D=E6=9C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- internal/service/order/service.go | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/internal/service/order/service.go b/internal/service/order/service.go index f5a1ba1..0634690 100644 --- a/internal/service/order/service.go +++ b/internal/service/order/service.go @@ -51,6 +51,7 @@ type Service struct { wechatPayment wechat.PaymentServiceInterface queueClient *queue.Client logger *zap.Logger + resumeCallback packagepkg.ResumeCallback } func New( @@ -95,6 +96,11 @@ func New( } } +// SetResumeCallback 设置复机回调,支付成功激活套餐后触发自动复机 +func (s *Service) SetResumeCallback(callback packagepkg.ResumeCallback) { + s.resumeCallback = callback +} + // CreateLegacy 创建订单(已废弃) // Deprecated: 使用 CreateAdminOrder 或 CreateH5Order 替代。保留用于回滚。 func (s *Service) CreateLegacy(ctx context.Context, req *dto.CreateOrderRequest, buyerType string, buyerID uint) (*dto.OrderResponse, error) { @@ -1621,10 +1627,53 @@ func (s *Service) HandlePaymentCallback(ctx context.Context, orderNo string, pay return err } + s.tryResumeAfterPayment(ctx, order) s.enqueueCommissionCalculation(ctx, order.ID) return nil } +// tryResumeAfterPayment 支付成功后检查是否应触发自动复机 +// 仅当本次支付直接激活了主套餐(status=1,非排队)时才调用复机,避免虚流量已超但套餐排队时错误复机 +func (s *Service) tryResumeAfterPayment(ctx context.Context, order *model.Order) { + if s.resumeCallback == nil { + return + } + + var resumeCarrierType string + var resumeCarrierID uint + + if order.OrderType == model.OrderTypeSingleCard && order.IotCardID != nil { + resumeCarrierType = "iot_card" + resumeCarrierID = *order.IotCardID + } else if order.OrderType == model.OrderTypeDevice && order.DeviceID != nil { + resumeCarrierType = "device" + resumeCarrierID = *order.DeviceID + } + + if resumeCarrierID == 0 { + return + } + + var activatedCount int64 + s.db.WithContext(ctx).Model(&model.PackageUsage{}). + Where("order_id = ? AND status = ? AND master_usage_id IS NULL", order.ID, constants.PackageUsageStatusActive). + Count(&activatedCount) + + if activatedCount == 0 { + return + } + + go func(ct string, cid uint) { + if err := s.resumeCallback.ResumeCardIfStopped(context.Background(), ct, cid); err != nil { + s.logger.Error("支付后自动复机失败", + zap.String("carrier_type", ct), + zap.Uint("carrier_id", cid), + zap.Uint("order_id", order.ID), + zap.Error(err)) + } + }(resumeCarrierType, resumeCarrierID) +} + func (s *Service) activatePackage(ctx context.Context, tx *gorm.DB, order *model.Order) error { var items []*model.OrderItem if err := tx.Where("order_id = ?", order.ID).Find(&items).Error; err != nil {