package biz import ( "context" "errors" "fmt" "gorm.io/gorm" errPb "voucher/api/err" "voucher/internal/biz/bo" "voucher/internal/biz/vo" "voucher/internal/pkg/lock" ) func (this *VoucherBiz) WechatNotifyConsumer(ctx context.Context, tag string, req *bo.WechatVoucherNotifyBo) error { c := vo.WechatNotifyConsumeLockKey.BuildCache([]string{tag, req.PlainText.StockID, req.PlainText.CouponID}) return lock.NewMutex(this.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error { order, err := this.getOrder(ctx, req) if err != nil { return err } if req.PlainText.Status.IsSended() { return this.available(ctx, order) } else if req.PlainText.Status.IsUsed() { return this.notifyUsed(ctx, order, req) } else if req.PlainText.Status.IsExpired() { return this.expired(ctx, order) } return fmt.Errorf("未知通知类型:%s", req.PlainText.Status.GetText()) }) } func (this *VoucherBiz) getOrder(ctx context.Context, req *bo.WechatVoucherNotifyBo) (*bo.OrderBo, error) { order, err := this.OrderRepo.GetByCouponId(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.CouponID) if err != nil { if !errors.Is(err, gorm.ErrRecordNotFound) { return nil, err } order, err = this.OrderRepo.GetByTransactionId(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.ConsumeInformation.TransactionID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("微信回调消费,订单不存在,StockCreatorMchid:%s,StockID:%s,CouponID:%s,CreateTime:%s", req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.CouponID, req.PlainText.CreateTime, ) } return nil, err } return order, nil } return order, nil } func (this *VoucherBiz) notifyUsed(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error { if order.Status.IsUse() { // 券状态已是已使用,忽略不处理 return nil } if err := this.OrderRepo.NotifyUsed(ctx, order.ID, req.PlainText.ConsumeInformation.TransactionID); err != nil { return err } return this.notify(ctx, order) } func (this *VoucherBiz) available(ctx context.Context, order *bo.OrderBo) error { if order.Status.IsSuccess() { // 券状态已是可使用,忽略不处理 return nil } if err := this.OrderRepo.Available(ctx, order.ID); err != nil { return err } return this.notify(ctx, order) } func (this *VoucherBiz) expired(ctx context.Context, order *bo.OrderBo) error { if order.Status.IsExpired() { // 券状态已是已过期,忽略不处理 return nil } if err := this.OrderRepo.Expired(ctx, order.ID); err != nil { return err } return this.notify(ctx, order) } func (this *VoucherBiz) notify(ctx context.Context, order *bo.OrderBo) error { if order.ActivityId == "" { return nil // 多笔立减活动,不做通知(?不知道有没有核销通知,多笔核销情况未知) } return this.cmbNotify(ctx, order.ID) } func (this *VoucherBiz) cmbNotify(ctx context.Context, orderId uint64) error { order, err := this.OrderRepo.GetByID(ctx, orderId) if err != nil { return err } if orderNotify, err2 := this.Cmb.Notify(ctx, order); err != nil { if !errPb.IsNeedRetryNotify(err2) { return err2 } // 第一次通知失败重试入队 // 状态回调接口失败需要支持重试 重试间隔为1分钟、2分钟、12分钟、60分钟、360分钟 return this.PushNotifyRetryDelayMQ(ctx, 60, orderNotify.ID) } return nil }