voucher/internal/biz/multi.go

269 lines
7.2 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 biz
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/go-kratos/kratos/v2/log"
"gorm.io/gorm"
"time"
v1 "voucher/api/v1"
"voucher/internal/biz/bo"
"voucher/internal/biz/cmb"
"voucher/internal/biz/mixrepos"
"voucher/internal/biz/repo"
"voucher/internal/biz/vo"
"voucher/internal/conf"
"voucher/internal/data"
"voucher/internal/pkg/lock"
)
type MultiBiz struct {
bc *conf.Bootstrap
rdb *data.Rdb
Cmb *cmb.Cmb
ProductRepo repo.ProductRepo
OrderRepo repo.OrderRepo
MultiNotifyDataRepo repo.MultiNotifyDataRepo
MultiNotifyLogRepo repo.MultiNotifyLogRepo
CmbMixRepo mixrepos.CmbMixRepo
}
func NewMultiBiz(
bc *conf.Bootstrap,
rdb *data.Rdb,
cmb *cmb.Cmb,
productRepo repo.ProductRepo,
orderRepo repo.OrderRepo,
multiNotifyDataRepo repo.MultiNotifyDataRepo,
multiNotifyLogRepo repo.MultiNotifyLogRepo,
cmbMixRepo mixrepos.CmbMixRepo,
) *MultiBiz {
return &MultiBiz{
bc: bc,
rdb: rdb,
Cmb: cmb,
ProductRepo: productRepo,
OrderRepo: orderRepo,
MultiNotifyDataRepo: multiNotifyDataRepo,
MultiNotifyLogRepo: multiNotifyLogRepo,
CmbMixRepo: cmbMixRepo,
}
}
func (biz *MultiBiz) Notify(ctx context.Context, source string, req *bo.WechatVoucherNotifyBo) error {
cl := vo.MultiNotifyLockKey.BuildCache([]string{
source,
req.PlainText.StockCreatorMchid,
req.PlainText.StockID,
req.PlainText.CouponID,
})
return lock.NewMutex(biz.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
order, err := biz.order(ctx, req)
if err != nil {
log.Errorf("[%s] multi notify error: %v,req:%+v", source, err, req)
return err
}
if err = biz.Run(ctx, source, req, order); err != nil {
log.Errorf("[%s] multi notify error: %v,req:%+v", source, err, req)
return err
}
return nil
})
}
func (biz *MultiBiz) order(ctx context.Context, req *bo.WechatVoucherNotifyBo) (*bo.OrderBo, error) {
order, err := biz.OrderRepo.GetByCouponId(ctx, req.PlainText.StockCreatorMchid, req.PlainText.StockID, req.PlainText.CouponID)
if err != nil {
return nil, fmt.Errorf("订单查询错误 error: %v", err)
}
return order, nil
}
func (biz *MultiBiz) Run(ctx context.Context, source string, req *bo.WechatVoucherNotifyBo, order *bo.OrderBo) error {
if order.ActivityId == "" {
return fmt.Errorf("批次活动ID为空不是多笔立减金请检查")
}
mnd, err := biz.MultiNotifyDataRepo.GetByNotifyID(ctx, req.ID)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("查询通知数据错误 error: %v", err)
}
if mnd != nil {
if mnd.NoticeNum > 0 {
log.Warnf("[%s] multi notify log already exists,req:%+v", source, req)
return nil
}
} else {
mnd, err = biz.mndCreate(ctx, source, req, order)
if err != nil {
return fmt.Errorf("创建通知数据错误 error: %v", err)
}
}
nl, err := biz.nlCreate(ctx, req, mnd, order)
if err != nil {
return fmt.Errorf("创建通知日志错误 error: %v", err)
}
return biz.Request(ctx, mnd, nl)
}
func (biz *MultiBiz) mndCreate(ctx context.Context, source string, req *bo.WechatVoucherNotifyBo, order *bo.OrderBo) (*bo.MultiNotifyDataBo, error) {
originalData, err := req.Str()
if err != nil {
return nil, fmt.Errorf("通知数据 json str 错误 error: %v", err)
}
return biz.MultiNotifyDataRepo.Create(ctx, &bo.MultiNotifyDataBo{
Source: source,
NotifyID: req.ID,
OrderNo: order.OrderNo,
OutBizNo: order.OutBizNo,
CouponID: req.PlainText.CouponID,
StockID: req.PlainText.StockID,
ConsumeAmount: int32(req.PlainText.ConsumeInformation.ConsumeAmount),
ConsumeTime: &req.PlainText.ConsumeInformation.ConsumeTime,
EventType: req.EventType,
OriginalData: originalData,
})
}
func (biz *MultiBiz) nlCreate(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo) (*bo.MultiNotifyLogBo, error) {
nl := &bo.MultiNotifyLogBo{
MultiNotifyDataID: mnd.ID,
OrderNo: mnd.OrderNo,
OutBizNo: mnd.OutBizNo,
CouponID: mnd.CouponID,
ActivityNo: order.ProductNo,
StockID: mnd.StockID,
EventType: mnd.EventType,
Status: req.PlainText.Status.GetValue(),
ConsumeAmount: mnd.ConsumeAmount,
ConsumeTime: mnd.ConsumeTime,
TransactionID: req.PlainText.ConsumeInformation.TransactionID,
RequestURL: order.NotifyUrl,
RequestStatus: vo.MultiNotifyLogStatusWait.GetValue(),
OrderCreateTime: order.CreateTime,
CouponCreateTime: &req.PlainText.CreateTime,
}
request, err := biz.GetRequest(ctx, nl)
if err != nil {
return nil, err
}
b, _ := json.Marshal(request)
nl.Request = string(b)
return biz.MultiNotifyLogRepo.Create(ctx, nl)
}
func (biz *MultiBiz) bizContent(nl *bo.MultiNotifyLogBo) (string, error) {
req := &v1.CmbNotifyRequest{ // 待确定
Ticket: nl.OrderNo,
TransDate: "", // 格式yyyy-mm-dd hh:mm:ss.sss
OrgNo: biz.bc.Cmb.OrgNo,
//Attach: nl.Attach,
Ext: "",
}
if nl.ConsumeTime != nil {
req.TransDate = nl.ConsumeTime.Format("2006-01-02 15:04:05.000")
} else {
req.TransDate = time.Now().Format("2006-01-02 15:04:05.000")
}
bizJsonBytes, err := json.Marshal(req)
if err != nil {
return "", err
}
return string(bizJsonBytes), nil
}
func (biz *MultiBiz) GetRequest(ctx context.Context, nl *bo.MultiNotifyLogBo) (*v1.CmbRequest, error) {
bizContent, err := biz.bizContent(nl)
if err != nil {
return nil, err
}
request, err := biz.CmbMixRepo.GetRequest(ctx, &bo.CmbRequestBo{
FuncName: vo.CmbNotifyFuncName, // 待确定
BizContent: bizContent,
})
if err != nil {
return nil, err
}
return request, nil
}
func (biz *MultiBiz) Request(ctx context.Context, mmd *bo.MultiNotifyDataBo, nl *bo.MultiNotifyLogBo) error {
if nl.RequestURL == "" {
if err := biz.notifyFail(ctx, nl, "回调通知招行地址为空"); err != nil {
return err
}
// 回调通知地址为空,不反回错误,不做再次通知处理
return nil
}
request, err := biz.GetRequest(ctx, nl)
if err != nil {
return err
}
reply, err := biz.CmbMixRepo.Request(ctx, request, nl.RequestURL)
if err != nil {
if err2 := biz.notifyFail(ctx, nl, err.Error()); err2 != nil {
return err2
}
return err
}
if err = biz.CmbMixRepo.VerifyResponse(ctx, reply); err != nil {
errMsg := fmt.Sprintf("回调通知招行返回验证结果发生错误,resp:%+v error:%s", reply, err.Error())
if err2 := biz.notifyFail(ctx, nl, errMsg); err2 != nil {
return err2
}
return err
}
return biz.notifySuccess(ctx, mmd, nl, reply)
}
func (biz *MultiBiz) notifyFail(ctx context.Context, nl *bo.MultiNotifyLogBo, remark string) error {
return biz.MultiNotifyLogRepo.Fail(ctx, nl.ID, remark)
}
func (biz *MultiBiz) notifySuccess(ctx context.Context, mmd *bo.MultiNotifyDataBo, nl *bo.MultiNotifyLogBo, reply *v1.CmbReply) error {
response, err := json.Marshal(reply)
if err != nil {
return err
}
if err = biz.MultiNotifyLogRepo.Success(ctx, nl.ID, string(response)); err != nil {
return err
}
if err = biz.MultiNotifyDataRepo.AddNoticeNum(ctx, mmd.ID); err != nil {
return err
}
return nil
}