238 lines
6.4 KiB
Go
238 lines
6.4 KiB
Go
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)
|
||
}
|