voucher/internal/biz/cmb/order_consume.go

238 lines
6.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package cmb
import (
"context"
"errors"
"fmt"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"voucher/internal/biz/bo"
"voucher/internal/biz/vo"
"voucher/internal/pkg/lock"
"voucher/internal/pkg/uid"
)
func (v *Cmb) OrderConsume(ctx context.Context, order *bo.OrderBo) (outRequestNo string, err error) {
if !order.Status.IsWait() {
return outRequestNo, fmt.Errorf("订单状态错误,%s", order.Status.GetText())
}
if !order.Channel.IsWeChat() {
return outRequestNo, fmt.Errorf("订单渠道错误,%s", order.Channel.GetText())
}
// 注册通知标签 order.MerchantNo 批次创建商户, order.BatchNo 商品批次号
if err = v.registerNotifyTag(ctx, order.MerchantNo, order.BatchNo); err != nil {
return outRequestNo, err
}
if err = v.ing(ctx, order.ID); err != nil {
return
}
orderWechat, err := v.create(ctx, order)
if err != nil {
return
}
couponId, err := v.WechatCpnRepo.Order(ctx, orderWechat)
if err != nil {
return outRequestNo, v.fail(ctx, order, orderWechat, err.Error())
}
if err = v.success(ctx, order, orderWechat, couponId); err != nil {
return
}
return orderWechat.OutRequestNo, err
}
func (v *Cmb) registerNotifyTag(ctx context.Context, stockCreatorMchID, stockID string) error {
c := vo.WechatNotifyRegisterTagCacheKey.BuildCache([]string{v.bc.WechatNotifyMQ.Tag, stockCreatorMchID, stockID})
_, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err == nil {
// 缓存存在,直接返回
return nil
}
if err != redis.Nil {
errMsg := fmt.Sprintf("获取redis缓存%s异常:%v", c.Key, err)
return fmt.Errorf(errMsg)
}
cl := vo.WechatNotifyRegisterTagCacheLockKey.BuildCache([]string{v.bc.WechatNotifyMQ.Tag, stockCreatorMchID, stockID})
return lock.NewMutex(v.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
// 二次获取,判定处理,以免获取锁后又执行了一次
cacheValue, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err != nil && err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("二次获取redis缓存%s异常:%v", c.Key, err))
}
if cacheValue != "" {
return nil // 有直接返回
}
wechatNotifyTag, err := v.WechatNotifyRegisterTagRepo.GetByStockIdAndMchId(ctx, stockCreatorMchID, stockID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if wechatNotifyTag != nil {
return v.setCache(ctx, c, wechatNotifyTag)
}
wechatNotifyTag, err = v.createWechatNotifyRegisterTag(ctx, stockCreatorMchID, stockID)
if err != nil {
return err
}
if err = v.WechatCpnRepo.RegisterNotifyTag(ctx, stockID); err != nil {
return v.WechatNotifyRegisterTagRepo.Fail(ctx, wechatNotifyTag.ID, err.Error())
}
if err = v.WechatNotifyRegisterTagRepo.Success(ctx, wechatNotifyTag.ID); err != nil {
return err
}
return v.setCache(ctx, c, wechatNotifyTag)
})
}
func (v *Cmb) createWechatNotifyRegisterTag(ctx context.Context, stockCreatorMchID, stockID string) (*bo.WechatNotifyRegisterTagBo, error) {
return v.WechatNotifyRegisterTagRepo.Create(ctx, &bo.WechatNotifyRegisterTagBo{
StockID: stockID,
StockCreatorMchID: stockCreatorMchID,
Tag: v.bc.WechatNotifyMQ.Tag,
})
}
func (v *Cmb) setCache(ctx context.Context, c *vo.Cache, wechatNotifyTag *bo.WechatNotifyRegisterTagBo) error {
if err := v.rdb.Rdb.Set(ctx, c.Key, wechatNotifyTag.Tag, c.TTL).Err(); err != nil {
return fmt.Errorf(fmt.Sprintf("设置redis缓存%s异常:%v", c.Key, err))
}
return nil
}
func (v *Cmb) create(ctx context.Context, order *bo.OrderBo) (*bo.OrderWechatBo, error) {
outRequestNo, err := v.GenerateMixRepo.GeneratorString(ctx, uid.OrderWechat)
if err != nil {
return nil, err
}
req := &bo.OrderWechatBo{
OrderNo: order.OrderNo,
OutRequestNo: outRequestNo,
AppID: order.AppID,
StockCreatorMchid: order.MerchantNo,
OpenID: order.Account,
StockID: order.BatchNo,
Status: vo.OrderWechatStatusWait,
}
orderWechat, err := v.OrderWechatRepo.Create(ctx, req)
if err != nil {
return nil, err
}
return orderWechat, nil
}
func (v *Cmb) ing(ctx context.Context, id uint64) error {
return v.OrderRepo.Ing(ctx, id)
}
func (v *Cmb) success(ctx context.Context, order *bo.OrderBo, orderWechat *bo.OrderWechatBo, couponId string) error {
if err := v.OrderWechatRepo.Success(ctx, orderWechat.ID, couponId); err != nil {
return err
}
return v.OrderRepo.Success(ctx, order.ID)
}
func (v *Cmb) fail(ctx context.Context, order *bo.OrderBo, orderWechat *bo.OrderWechatBo, errMsg string) error {
if err := v.OrderWechatRepo.Fail(ctx, orderWechat.ID, errMsg); err != nil {
return err
}
if err := v.OrderRepo.Fail(ctx, order.ID); err != nil {
return err
}
return v.alarm(ctx, order, errMsg)
}
func (v *Cmb) alarm(ctx context.Context, order *bo.OrderBo, errMsg string) error {
// 1小时 内 指定的批次号 发放 发生错误 预警
c := vo.OrderConsumeFailAlarmKey.BuildCache([]string{order.ProductNo})
_, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err == nil {
// 缓存存在,直接返回
return nil
}
if err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("alarm 获取redis缓存%s异常:%v", c.Key, err))
}
cl := vo.OrderConsumeFailAlarmLockKey.BuildCache([]string{order.ProductNo})
return lock.NewMutex(v.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
// 二次获取,判定处理,以免获取锁后又执行了一次
cacheValue, err := v.rdb.Rdb.Get(ctx, c.Key).Result()
if err != nil && err != redis.Nil {
return fmt.Errorf(fmt.Sprintf("alarm 二次获取redis缓存%s异常:%v", c.Key, err))
}
if cacheValue != "" {
return nil // 有直接返回
}
// 通知
text := v.alarmText(ctx, order, errMsg)
if err = v.DingMixRepo.SendMarkdownMessage(ctx, text); err != nil {
return err
}
if err := v.rdb.Rdb.Set(ctx, c.Key, order.ProductNo, c.TTL).Err(); err != nil {
return fmt.Errorf(fmt.Sprintf("设置redis缓存%s异常:%v", c.Key, err))
}
return nil
})
}
func (v *Cmb) alarmText(_ context.Context, order *bo.OrderBo, errMsg string) string {
remarks := fmt.Sprintf("订单号:%s商品编号:%s,错误原因:%s", order.OrderNo, order.ProductNo, errMsg)
msg := "# <font color='green'>" +
"<h1>立减金发放平台报警通知</h1>" +
"</font> \n" +
"<font color='black'>" +
"不好了,订单发放发生异常了,错误内容" +
"[<font color='red'>%s</font>]@相关人员。" +
"</font>"
return fmt.Sprintf(msg, remarks)
}