feat(multi-notify): 增加合单支付回调
This commit is contained in:
parent
b5b07a4d79
commit
5e4b072062
|
|
@ -22,6 +22,8 @@ Thumbs.db
|
|||
*.swp
|
||||
.vscode/
|
||||
.idea/
|
||||
.trae/
|
||||
|
||||
bin/
|
||||
cert/
|
||||
log
|
||||
|
|
|
|||
|
|
@ -16,6 +16,19 @@ type ConsumeInformation struct {
|
|||
ConsumeAmount int `json:"consume_amount"` // 核销金额(单位:分) // 多笔立减金必须 validate:"required"
|
||||
}
|
||||
|
||||
// CombineSubOrder 定义合单子单消费信息结构体
|
||||
type CombineSubOrder struct {
|
||||
TransactionID string `json:"transaction_id" validate:"required"` // 合单子单微信支付订单号
|
||||
ConsumeAmount int `json:"comsume_amount" validate:"required"` // 子单核销金额,微信文档字段名如此定义
|
||||
ConsumeTime time.Time `json:"consume_time" validate:"required"` // 子单核销时间
|
||||
}
|
||||
|
||||
// CombineOrderInfo 定义合单订单信息结构体
|
||||
type CombineOrderInfo struct {
|
||||
CombineConsumeAmount int `json:"combine_consume_amount"` // 合单总核销金额
|
||||
SubOrders []CombineSubOrder `json:"sub_orders,omitempty"` // 合单子单列表
|
||||
}
|
||||
|
||||
// PlainText 定义明文数据结构体
|
||||
type PlainText struct {
|
||||
StockCreatorMchid string `json:"stock_creator_mchid" validate:"required"`
|
||||
|
|
@ -29,7 +42,9 @@ type PlainText struct {
|
|||
NoCash bool `json:"no_cash"`
|
||||
Singleitem bool `json:"singleitem"`
|
||||
BusinessType string `json:"business_type"` // 业务类型
|
||||
IsCombineOrder bool `json:"is_combine_order,omitempty"`
|
||||
ConsumeInformation *ConsumeInformation `json:"consume_information,omitempty"`
|
||||
CombineOrderInfo *CombineOrderInfo `json:"combine_order_info,omitempty"`
|
||||
}
|
||||
|
||||
type WechatVoucherNotifyBo struct {
|
||||
|
|
@ -63,3 +78,39 @@ func (c *WechatVoucherNotifyBo) Validate() error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *WechatVoucherNotifyBo) ValidateMultiNotify() error {
|
||||
if err := c.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.PlainText.IsCombineOrder {
|
||||
if c.PlainText.CombineOrderInfo == nil {
|
||||
return fmt.Errorf("合单订单信息不能为空")
|
||||
}
|
||||
if len(c.PlainText.CombineOrderInfo.SubOrders) == 0 {
|
||||
return fmt.Errorf("合单子单不能为空")
|
||||
}
|
||||
for _, subOrder := range c.PlainText.CombineOrderInfo.SubOrders {
|
||||
if subOrder.TransactionID == "" {
|
||||
return fmt.Errorf("合单子单微信支付订单号不能为空")
|
||||
}
|
||||
if subOrder.ConsumeAmount <= 0 {
|
||||
return fmt.Errorf("合单子单核销金额必须大于0")
|
||||
}
|
||||
if subOrder.ConsumeTime.IsZero() {
|
||||
return fmt.Errorf("合单子单核销时间不能为空")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.PlainText.ConsumeInformation == nil {
|
||||
return fmt.Errorf("消费信息不能为空")
|
||||
}
|
||||
if c.PlainText.ConsumeInformation.ConsumeAmount <= 0 {
|
||||
return fmt.Errorf("消费金额必须大于0")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ func (biz *MultiBiz) Notify(ctx context.Context, ip, source string, req *bo.Wech
|
|||
|
||||
return lock.NewMutex(biz.rdb.Rdb, cl.TTL).Lock(ctx, cl.Key, func(ctx context.Context) error {
|
||||
|
||||
if req.PlainText.ConsumeInformation.ConsumeAmount == 0 {
|
||||
return fmt.Errorf("消费金额不能为0")
|
||||
if err = req.ValidateMultiNotify(); err != nil {
|
||||
return fmt.Errorf("multi validate req error: %v", err)
|
||||
}
|
||||
|
||||
order, err := biz.order(ctx, req)
|
||||
|
|
@ -115,7 +115,7 @@ func (biz *MultiBiz) Run(ctx context.Context, ip, source string, req *bo.WechatV
|
|||
}
|
||||
|
||||
if mnd != nil {
|
||||
if mnd.NoticeNum > 0 {
|
||||
if !req.PlainText.IsCombineOrder && mnd.NoticeNum > 0 {
|
||||
log.Warnf("[%s] multi notify log already exists,req:%+v", source, req)
|
||||
return nil
|
||||
}
|
||||
|
|
@ -150,6 +150,14 @@ func (biz *MultiBiz) RetryRunByMultiNotifyDataId(ctx context.Context, multiNotif
|
|||
}
|
||||
|
||||
func (biz *MultiBiz) run(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo) error {
|
||||
if req.PlainText.IsCombineOrder {
|
||||
return biz.runCombine(ctx, req, mnd, order)
|
||||
}
|
||||
|
||||
return biz.runSingle(ctx, req, mnd, order)
|
||||
}
|
||||
|
||||
func (biz *MultiBiz) runSingle(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo) error {
|
||||
// 如果核销金额为空,不再推送下游
|
||||
if mnd.ConsumeAmount == 0 {
|
||||
log.Warnf("[%s] multi notify log consume amount is 0,req:%+v", mnd.NotifyID, req)
|
||||
|
|
@ -165,20 +173,50 @@ func (biz *MultiBiz) run(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd
|
|||
return fmt.Errorf("请求错误 error: %v", err)
|
||||
}
|
||||
|
||||
return biz.updateOrderStatus(ctx, req, order)
|
||||
}
|
||||
|
||||
func (biz *MultiBiz) runCombine(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo) error {
|
||||
for _, subOrder := range req.PlainText.CombineOrderInfo.SubOrders {
|
||||
exists, err := biz.MultiNotifyLogRepo.ExistsSuccessByDataIDAndTransactionID(ctx, mnd.ID, subOrder.TransactionID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询合单子单通知记录错误 error: %v", err)
|
||||
}
|
||||
if exists {
|
||||
log.Warnf("[%s] combine sub order already notified,transaction_id:%s", mnd.NotifyID, subOrder.TransactionID)
|
||||
continue
|
||||
}
|
||||
|
||||
nl, request, err := biz.nlCreateBySubOrder(ctx, req, mnd, order, subOrder)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建合单子单通知日志错误 error: %v", err)
|
||||
}
|
||||
|
||||
if err = biz.Request(ctx, mnd, nl, request); err != nil {
|
||||
return fmt.Errorf("合单子单请求错误 error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return biz.updateOrderStatus(ctx, req, order)
|
||||
}
|
||||
|
||||
func (biz *MultiBiz) updateOrderStatus(ctx context.Context, req *bo.WechatVoucherNotifyBo, order *bo.OrderBo) error {
|
||||
consumeTime := req.PlainText.ConsumeInformation.ConsumeTime
|
||||
|
||||
if req.PlainText.Status.IsUsed() {
|
||||
|
||||
if order.Status.IsUse() {
|
||||
if err = biz.OrderRepo.MultiOverUsed(ctx, order.ID, req.PlainText.ConsumeInformation.ConsumeTime, "再次核销完成"); err != nil {
|
||||
if err := biz.OrderRepo.MultiOverUsed(ctx, order.ID, consumeTime, "再次核销完成"); err != nil {
|
||||
return fmt.Errorf("订单再次核销完成修改发生错误 error: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err = biz.OrderRepo.MultiOverUsed(ctx, order.ID, req.PlainText.ConsumeInformation.ConsumeTime, "核销完成"); err != nil {
|
||||
if err := biz.OrderRepo.MultiOverUsed(ctx, order.ID, consumeTime, "核销完成"); err != nil {
|
||||
return fmt.Errorf("订单核销完成修改发生错误 error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if err = biz.OrderRepo.MultiLastUsed(ctx, order.ID, req.PlainText.ConsumeInformation.ConsumeTime); err != nil {
|
||||
if err := biz.OrderRepo.MultiLastUsed(ctx, order.ID, consumeTime); err != nil {
|
||||
return fmt.Errorf("订单核销修改发生错误 error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -193,6 +231,13 @@ func (biz *MultiBiz) mndCreate(ctx context.Context, ip, source string, req *bo.W
|
|||
return nil, fmt.Errorf("通知数据 json str 错误 error: %v", err)
|
||||
}
|
||||
|
||||
consumeAmount := int32(req.PlainText.ConsumeInformation.ConsumeAmount)
|
||||
consumeTime := &req.PlainText.ConsumeInformation.ConsumeTime
|
||||
transactionID := req.PlainText.ConsumeInformation.TransactionID
|
||||
if req.PlainText.IsCombineOrder {
|
||||
consumeAmount = int32(req.PlainText.CombineOrderInfo.CombineConsumeAmount)
|
||||
}
|
||||
|
||||
return biz.MultiNotifyDataRepo.Create(ctx, &bo.MultiNotifyDataBo{
|
||||
Source: source,
|
||||
IP: ip,
|
||||
|
|
@ -201,15 +246,57 @@ func (biz *MultiBiz) mndCreate(ctx context.Context, ip, source string, req *bo.W
|
|||
OutBizNo: order.OutBizNo,
|
||||
CouponID: req.PlainText.CouponID,
|
||||
StockID: req.PlainText.StockID,
|
||||
ConsumeAmount: int32(req.PlainText.ConsumeInformation.ConsumeAmount),
|
||||
ConsumeTime: &req.PlainText.ConsumeInformation.ConsumeTime,
|
||||
TransactionID: req.PlainText.ConsumeInformation.TransactionID,
|
||||
ConsumeAmount: consumeAmount,
|
||||
ConsumeTime: consumeTime,
|
||||
TransactionID: transactionID,
|
||||
EventType: req.EventType,
|
||||
Status: req.PlainText.Status,
|
||||
OriginalData: originalData,
|
||||
})
|
||||
}
|
||||
|
||||
func (biz *MultiBiz) nlCreateBySubOrder(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo, subOrder bo.CombineSubOrder) (*bo.MultiNotifyLogBo, *v1.CmbRequest, error) {
|
||||
if biz.bc.Cmb.MultiNotifyUrl == "" {
|
||||
return nil, nil, fmt.Errorf("CMB多笔立减金通知地址为空")
|
||||
}
|
||||
|
||||
consumeTime := subOrder.ConsumeTime
|
||||
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,
|
||||
ConsumeAmount: int32(subOrder.ConsumeAmount),
|
||||
ConsumeTime: &consumeTime,
|
||||
TransactionID: subOrder.TransactionID,
|
||||
RequestURL: biz.bc.Cmb.MultiNotifyUrl,
|
||||
RequestStatus: vo.MultiNotifyLogStatusWait.GetValue(),
|
||||
OrderCreateTime: order.CreateTime,
|
||||
CouponCreateTime: &req.PlainText.CreateTime,
|
||||
}
|
||||
|
||||
request, cmbRequestBo, err := biz.GetRequest(ctx, nl, order)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
b, _ := json.Marshal(request)
|
||||
nl.OriginReq = cmbRequestBo.BizContent
|
||||
nl.Request = string(b)
|
||||
|
||||
res, err := biz.MultiNotifyLogRepo.Create(ctx, nl)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("创建通知日志错误 error: %v", err)
|
||||
}
|
||||
res.ConsumeTime = nl.ConsumeTime
|
||||
|
||||
return res, request, nil
|
||||
}
|
||||
|
||||
func (biz *MultiBiz) nlCreate(ctx context.Context, req *bo.WechatVoucherNotifyBo, mnd *bo.MultiNotifyDataBo, order *bo.OrderBo) (*bo.MultiNotifyLogBo, *v1.CmbRequest, error) {
|
||||
|
||||
if biz.bc.Cmb.MultiNotifyUrl == "" {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
type MultiNotifyLogRepo interface {
|
||||
Create(ctx context.Context, req *bo.MultiNotifyLogBo) (*bo.MultiNotifyLogBo, error)
|
||||
GetByID(ctx context.Context, id int64) (*bo.MultiNotifyLogBo, error)
|
||||
ExistsSuccessByDataIDAndTransactionID(ctx context.Context, multiNotifyDataID int64, transactionID string) (bool, error)
|
||||
Success(ctx context.Context, id int64, response string) error
|
||||
Fail(ctx context.Context, id int64, remark string) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ func (this *VoucherBiz) WechatNotifyConsumer(ctx context.Context, ip string, req
|
|||
}
|
||||
|
||||
if order.ActivityId != "" {
|
||||
if err = req.Validate(); err != nil {
|
||||
if err = req.ValidateMultiNotify(); err != nil {
|
||||
return fmt.Errorf("multi validate req error: %v", err)
|
||||
}
|
||||
return this.MultiBiz.Run(ctx, ip, req.PlainText.StockCreatorMchid, req, order)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ package repoimpl
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
err2 "voucher/api/err"
|
||||
|
|
@ -12,6 +12,8 @@ import (
|
|||
"voucher/internal/biz/vo"
|
||||
"voucher/internal/data"
|
||||
"voucher/internal/data/model"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// MultiNotifyLogRepoImpl .
|
||||
|
|
@ -77,6 +79,24 @@ func (p *MultiNotifyLogRepoImpl) GetByID(ctx context.Context, id int64) (*bo.Mul
|
|||
return p.ToBo(&item), nil
|
||||
}
|
||||
|
||||
func (p *MultiNotifyLogRepoImpl) ExistsSuccessByDataIDAndTransactionID(ctx context.Context, multiNotifyDataID int64, transactionID string) (bool, error) {
|
||||
var item model.MultiNotifyLog
|
||||
|
||||
err := p.DB(ctx).
|
||||
Select("id").
|
||||
Where("multi_notify_data_id = ? AND transaction_id = ? AND request_status = ?", multiNotifyDataID, transactionID, vo.MultiNotifyLogStatusSuccess.GetValue()).
|
||||
Limit(1).
|
||||
Take(&item).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *MultiNotifyLogRepoImpl) Success(ctx context.Context, id int64, response string) error {
|
||||
|
||||
now := time.Now()
|
||||
|
|
|
|||
Loading…
Reference in New Issue