196 lines
4.4 KiB
Go
196 lines
4.4 KiB
Go
package biz
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"gorm.io/gorm"
|
|
"time"
|
|
errPb "voucher/api/err"
|
|
"voucher/internal/biz/bo"
|
|
"voucher/internal/biz/vo"
|
|
"voucher/internal/pkg/lock"
|
|
)
|
|
|
|
func (v *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(v.rdb.Rdb, c.TTL).Lock(ctx, c.Key, func(ctx context.Context) error {
|
|
|
|
order, err := v.getOrder(ctx, req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if req.PlainText.Status.IsSended() {
|
|
|
|
return v.available(ctx, order)
|
|
|
|
} else if req.PlainText.Status.IsUsed() {
|
|
|
|
return v.notifyUsed(ctx, order, req)
|
|
|
|
} else if req.PlainText.Status.IsExpired() {
|
|
|
|
return v.expired(ctx, order)
|
|
|
|
}
|
|
|
|
return fmt.Errorf("未知通知类型:%s", req.PlainText.Status.GetText())
|
|
})
|
|
}
|
|
|
|
func (v *VoucherBiz) useLog(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {
|
|
|
|
if req.PlainText.ConsumeInformation.ConsumeTime == "" {
|
|
return nil
|
|
}
|
|
|
|
if req.PlainText.ConsumeInformation.ConsumeAmount > 0 {
|
|
if err := v.createUseLog(ctx, order, req); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *VoucherBiz) createUseLog(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {
|
|
|
|
useTime, err2 := time.Parse(time.RFC3339, req.PlainText.ConsumeInformation.ConsumeTime)
|
|
if err2 != nil {
|
|
return err2
|
|
}
|
|
|
|
useLog, err2 := v.UseLogRepo.GetByUseTimeOrder(ctx, order.OrderNo, &useTime)
|
|
|
|
if err2 != nil && !errors.Is(err2, gorm.ErrRecordNotFound) {
|
|
return err2
|
|
}
|
|
|
|
if useLog == nil {
|
|
_, err := v.UseLogRepo.Create(ctx, &bo.UseLogBo{
|
|
OrderNo: order.OrderNo,
|
|
Amount: req.PlainText.ConsumeInformation.ConsumeAmount,
|
|
Type: vo.UseLogTypeUsed,
|
|
OperateTime: &useTime,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
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",
|
|
req.PlainText.StockCreatorMchid,
|
|
req.PlainText.StockID,
|
|
req.PlainText.CouponID,
|
|
)
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
return order, nil
|
|
}
|
|
|
|
return order, nil
|
|
}
|
|
|
|
func (v *VoucherBiz) notifyUsed(ctx context.Context, order *bo.OrderBo, req *bo.WechatVoucherNotifyBo) error {
|
|
|
|
if order.Status.IsUse() {
|
|
// 券状态已是已使用,忽略不处理
|
|
return nil
|
|
}
|
|
|
|
if err := v.OrderRepo.NotifyUsed(ctx, order.ID, req.PlainText.ConsumeInformation.TransactionID); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := v.notify(ctx, order); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := v.useLog(ctx, order, req); err != nil {
|
|
return err
|
|
}
|
|
|
|
_ = v.wxToBBUse(ctx, order, req)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *VoucherBiz) available(ctx context.Context, order *bo.OrderBo) error {
|
|
|
|
if order.Status.IsSuccess() {
|
|
// 券状态已是可使用,忽略不处理
|
|
return nil
|
|
}
|
|
|
|
if err := v.OrderRepo.Available(ctx, order.ID); err != nil {
|
|
return err
|
|
}
|
|
|
|
return v.notify(ctx, order)
|
|
}
|
|
|
|
func (v *VoucherBiz) expired(ctx context.Context, order *bo.OrderBo) error {
|
|
|
|
if order.Status.IsExpired() {
|
|
// 券状态已是已过期,忽略不处理
|
|
return nil
|
|
}
|
|
|
|
if err := v.OrderRepo.Expired(ctx, order.ID); err != nil {
|
|
return err
|
|
}
|
|
|
|
//return v.notify(ctx, order)
|
|
return nil // 过期不做通知
|
|
}
|
|
|
|
func (v *VoucherBiz) notify(ctx context.Context, order *bo.OrderBo) error {
|
|
|
|
return v.cmbNotify(ctx, order.ID)
|
|
}
|
|
|
|
func (v *VoucherBiz) cmbNotify(ctx context.Context, orderId uint64) error {
|
|
|
|
order, err := v.OrderRepo.GetByID(ctx, orderId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if orderNotify, err2 := v.Cmb.Notify(ctx, order); err2 != nil {
|
|
|
|
if !errPb.IsNeedRetryNotify(err2) {
|
|
return err2
|
|
}
|
|
|
|
// 第一次通知失败重试入队
|
|
// 状态回调接口失败需要支持重试 重试间隔为1分钟、2分钟、12分钟、60分钟、360分钟
|
|
return v.PushNotifyRetryDelayMQ(ctx, 60, orderNotify.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|