feat: 修改天猫回调逻辑

This commit is contained in:
danial
2024-09-23 23:06:36 +08:00
parent 66e233f450
commit 47db435df8
13 changed files with 136 additions and 139 deletions

2
.gitignore vendored
View File

@@ -17,6 +17,6 @@ temp/
temp.yaml
bin
/resource/log/
# **/config/config.yaml
# **/config/config.yaml.bak2
main.exe~
/qodana.yaml

View File

@@ -6,7 +6,7 @@ import (
)
type TMallGameAgisoCallbackReq struct {
g.Meta `path:"/recharge/tMallGame/agiso/callback" tags:"阿奇索" method:"post" summary:"请求回调"`
g.Meta `path:"/recharge/tMallGame/agiso/callback" tags:"阿奇索" method:"post" summary:"阿奇索请求回调"`
FromPlatform string `json:"fromPlatform" description:"平台参数值TbAcs,TbAlds,TbArs,Print,Acpr,PddAlds,AldsIdle,AldsJd,AldsDoudian,AldsKwai,AldsYouzan,AldsWeidian,AldsWxVideoShop"`
TimeStamp int `json:"timeStamp" description:"时间戳"`
Aopic consts.AgisoCallbackStatus `json:"aopic" description:"推送类型"`

View File

@@ -5,7 +5,7 @@ include ./hack/hack-cli.mk
up: cli.install
@gf up -a
# Build binary using configuration from hack/config.yaml.
# Build binary using configuration from hack/config.yaml.bak2.
.PHONY: build
build: cli.install
@gf build -ew

View File

@@ -15,7 +15,7 @@ import (
"kami/internal/model"
"kami/internal/service"
"kami/utility/integration/agiso"
tmall "kami/utility/integration/tmall/api"
tmallAPI "kami/utility/integration/tmall/api"
)
func (c *ControllerV1) TMallGameAgisoCallback(ctx context.Context, req *v1.TMallGameAgisoCallbackReq) (res *v1.TMallGameAgisoCallbackRes, err error) {
@@ -26,61 +26,102 @@ func (c *ControllerV1) TMallGameAgisoCallback(ctx context.Context, req *v1.TMall
return
}
switch req.Aopic {
//买家付款
case consts.CALLBACK_PAYMENT_SUCCESS:
tbTradeBuyerPay := agiso.TBTradeBuyerPay{}
rechargeTMallGameOrder := service.RechargeTMallGameOrder()
if err = json.Unmarshal([]byte(req.Json), &tbTradeBuyerPay); err != nil {
err = errHandler.WrapError(ctx, gcode.CodeInternalError, gerror.Wrap(err, fmt.Sprintf("返回数据:%s", req.Json)), "json解析失败")
return
}
//写入订单
shopId, err2 := rechargeTMallGameOrder.AddAgisoCallBackBaseInfo(ctx, &model.AddAgisoCallBackBaseInfoInput{
TMallOrderId: tbTradeBuyerPay.Tid,
BuyerNick: tbTradeBuyerPay.BuyerNick,
Status: consts.RechargeTMallGameOrderStatusCallback,
Payment: tbTradeBuyerPay.Payment,
OriginalData: req.Json,
}, nil)
//向淘宝获取订单信息,需要的信息在淘宝备注里
tbTrade, err2 := tmall.NewClient().TBMallTradeGet(ctx, tbTradeBuyerPay.Tid)
if err2 != nil {
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err2, "淘宝订单信息获取失败")
return
}
glog.Info(ctx, "我被运行了")
glog.Info(ctx, "授权信息", tbTrade)
err2 = rechargeTMallGameOrder.UpdateTMallCallBackInfo(ctx, &model.UpdateAgisoCallBackInfoInput{
Id: shopId,
TMallOrderId: gconv.Int(tbTrade.Tid),
Created: gconv.GTime(tbTrade.Created),
BuyerNick: gconv.String(tbTrade.BuyerNick),
Status: consts.RechargeTMallGameOrderStatusPaid,
BuyerRate: gconv.Int(*tbTrade.BuyerRate),
TradeStatus: gconv.String(tbTrade.Status),
Payment: gconv.String(tbTrade.Payment),
TotalFee: gconv.String(tbTrade.TotalFee),
PayTime: gconv.GTime(&tbTrade.PayTime),
BuyerMemo: gconv.String(tbTrade.BuyerMemo),
AlipayNo: gconv.String(tbTrade.AlipayNo),
BuyerMessage: gconv.String(tbTrade.BuyerMessage),
OriginalData: string(gjson.MustEncode(tbTrade)),
SourceType: consts.RechargeTMallGameShopSourceTypeTMall,
}, nil)
if err2 != nil {
glog.Error(ctx, "更新阿奇索回调信息失败,返回数据", fmt.Sprintf("返回数据:%s", req.Json))
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "添加阿奇索细节信息失败")
return
}
//获取关联订单将shop订单关联到主订单中
err2 = rechargeTMallGameOrder.AssociateCreatedOrderAndStatus(ctx, &model.AssociateCreatedOrderAndStatusInput{
AccountNumber: gconv.String(tbTrade.BuyerMessage),
ShopId: shopId,
}, nil)
if err2 != nil {
glog.Error(ctx, fmt.Sprintf("返回数据:%s", req.Json), err2)
}
err = handleCallBackPaymentSuccess(ctx, req.Json)
default:
glog.Error(ctx, "未知的回调类型", req.Aopic, req.Json)
}
return
}
func handleCallBackPaymentSuccess(ctx context.Context, reqJson string) (err error) {
tbTradeBuyerPay := agiso.TBTradeBuyerPay{}
rechargeTMallGameOrder := service.RechargeTMallGameOrder()
if err = json.Unmarshal([]byte(reqJson), &tbTradeBuyerPay); err != nil {
err = errHandler.WrapError(ctx, gcode.CodeInternalError, gerror.Wrap(err, fmt.Sprintf("返回数据:%s", reqJson)), "json解析失败")
return
}
//判断当前订单是否已经推送过
if isExist, _ := rechargeTMallGameOrder.IsExist(ctx, gconv.Int64(tbTradeBuyerPay.Tid)); isExist {
err = gerror.New("订单已经存在,重复推送")
return
}
//写入基本shop订单
shopId, err2 := rechargeTMallGameOrder.AddAgisoCallBackBaseInfo(ctx, &model.AddAgisoCallBackBaseInfoInput{
TMallOrderId: tbTradeBuyerPay.Tid,
BuyerNick: tbTradeBuyerPay.BuyerNick,
Status: consts.RechargeTMallGameOrderStatusCallback,
Payment: tbTradeBuyerPay.Payment,
OriginalData: reqJson,
}, nil)
//向淘宝获取订单信息,需要的信息在淘宝备注里
tbTrade, err2 := tmallAPI.NewClient().TBMallTradeGet(ctx, tbTradeBuyerPay.Tid)
if err2 != nil {
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err2, "淘宝订单信息获取失败")
return
}
glog.Info(ctx, "我被运行了")
err2 = rechargeTMallGameOrder.UpdateTMallCallBackInfo(ctx, &model.UpdateAgisoCallBackInfoInput{
Id: shopId,
TMallOrderId: gconv.Int(tbTrade.Tid),
Created: gconv.GTime(tbTrade.Created),
BuyerNick: gconv.String(tbTrade.BuyerNick),
Status: consts.RechargeTMallGameOrderStatusPaid,
BuyerRate: gconv.Int(*tbTrade.BuyerRate),
TradeStatus: gconv.String(tbTrade.Status),
Payment: gconv.String(tbTrade.Payment),
TotalFee: gconv.String(tbTrade.TotalFee),
PayTime: gconv.GTime(&tbTrade.PayTime),
BuyerMemo: gconv.String(tbTrade.BuyerMemo),
AlipayNo: gconv.String(tbTrade.AlipayNo),
BuyerMessage: gconv.String(tbTrade.BuyerMessage),
OriginalData: string(gjson.MustEncode(tbTrade)),
SourceType: consts.RechargeTMallGameShopSourceTypeTMall,
}, nil)
if err2 != nil {
glog.Error(ctx, "更新阿奇索回调信息失败,返回数据", fmt.Sprintf("返回数据:%s", reqJson))
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "添加阿奇索细节信息失败")
return
}
//获取关联订单将shop订单关联到主订单中
err2 = rechargeTMallGameOrder.AssociateCreatedOrderAndStatus(ctx, &model.AssociateCreatedOrderAndStatusInput{
AccountNumber: gconv.String(tbTrade.BuyerMessage),
ShopId: shopId,
}, nil)
if err2 != nil {
glog.Error(ctx, fmt.Sprintf("返回数据:%s", reqJson), err2)
}
//查找对应订单
orderInfo, err2 := rechargeTMallGameOrder.GetByShopId(ctx, shopId, nil)
if err2 != nil {
glog.Error(ctx, "管理订单数据失败", err2)
return
}
if orderInfo.Amount != gconv.Float64(tbTradeBuyerPay.Payment) {
// 金额不符
err4 := rechargeTMallGameOrder.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: orderInfo.OrderNo,
Status: consts.RechargeTMallGameOrderStatusFinishedWithWrongAmount,
}, nil)
glog.Error(ctx, "更新订单数据失败", err4)
return
}
tMallClient := tmallAPI.NewClient()
glog.Info(ctx, "开始发货, 订单号:", orderInfo.OrderNo)
if isSucceed, err3 := tMallClient.VirtualDelivery(ctx, gconv.Int64(tbTrade.Tid)); !isSucceed || err3 != nil {
glog.Error(ctx, "虚拟发货失败", err3)
err4 := rechargeTMallGameOrder.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: orderInfo.OrderNo,
Status: consts.RechargeTMallGameOrderStatusDeliverySucceed,
}, nil)
glog.Error(ctx, "更新订单数据失败", err4)
} else {
err4 := rechargeTMallGameOrder.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: orderInfo.OrderNo,
Status: consts.RechargeTMallGameOrderStatusDeliveryFailed,
}, nil)
glog.Error(ctx, "更新订单数据失败", err4)
}
return
}

View File

@@ -46,7 +46,7 @@ func Test_sAppleAccount_GetAccordingAccount(t *testing.T) {
}
func Test_sAppleAccount_GetAccordingAccountV2(t *testing.T) {
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("/manifest/config/config.local.yaml")
g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("/manifest/config/config.yaml")
ctx := gctx.New()
data, err := New().GetAccordingAccountV2(ctx, "123456", decimal.NewFromInt(100))
if err != nil {

View File

@@ -61,7 +61,18 @@ func (h *sRechargeTMallGameOrder) GetById(ctx context.Context, orderNo string, t
return
}
// AssociateCreatedOrderAndStatus 关联相关订单
// GetByShopId 根据天猫订单关联查找对应订单
func (h *sRechargeTMallGameOrder) GetByShopId(ctx context.Context, shopOrderId int64, tx gdb.TX) (data *entity.V1RechargeTMallOrder, err error) {
data = &entity.V1RechargeTMallOrder{}
m := dao.V1RechargeTMallOrder.Ctx(ctx).DB(config.GetDatabaseV1())
if tx != nil {
m = m.TX(tx)
}
err = m.Where(dao.V1RechargeTMallOrder.Columns().TMallShopId, shopOrderId).Scan(&data)
return
}
// AssociateCreatedOrderAndStatus 淘宝订单相互关联
func (h *sRechargeTMallGameOrder) AssociateCreatedOrderAndStatus(ctx context.Context, input *model.AssociateCreatedOrderAndStatusInput, tx gdb.TX) (err error) {
m := dao.V1RechargeTMallOrder.Ctx(ctx).DB(config.GetDatabaseV1())
if tx != nil {
@@ -77,7 +88,8 @@ func (h *sRechargeTMallGameOrder) AssociateCreatedOrderAndStatus(ctx context.Con
}
if _, err2 := dao.V1RechargeTMallOrder.Ctx(ctx).DB(config.GetDatabaseV1()).TX(tx).
Where(dao.V1RechargeTMallOrder.Columns().Id, data.Id).Update(do.V1RechargeTMallOrder{
Status: consts.RechargeTMallGameOrderStatusPaid,
TMallShopId: input.ShopId,
Status: consts.RechargeTMallGameOrderStatusPaid,
}); err2 != nil {
return err2
}

View File

@@ -9,6 +9,7 @@ import (
"kami/internal/model/do"
"kami/internal/model/entity"
"kami/utility/config"
"kami/utility/utils"
)
// AddAgisoCallBackBaseInfo 返回阿奇索基基本回调数据
@@ -49,7 +50,7 @@ func (h *sRechargeTMallGameOrder) UpdateTMallCallBackInfo(ctx context.Context, i
m = m.TX(tx)
}
err = m.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
_, err2 := dao.V1RechargeTMallShop.Ctx(ctx).TX(tx).
_, err2 := dao.V1RechargeTMallShop.Ctx(ctx).TX(tx).DB(config.GetDatabaseV1()).
Where(dao.V1RechargeTMallShop.Columns().Id, input.Id).
Update(do.V1RechargeTMallShop{
OrderNo: input.OrderNo,
@@ -89,3 +90,11 @@ func (h *sRechargeTMallGameOrder) GetShopOne(ctx context.Context, shopOrderId in
err = dao.V1RechargeTMallShop.Ctx(ctx).Where(dao.V1RechargeTMallShop.Columns().Id, shopOrderId).Scan(&data)
return
}
// IsExist 判断当前订单是否存在
func (h *sRechargeTMallGameOrder) IsExist(ctx context.Context, tMallOrderNo int64) (bool, error) {
count, err := dao.V1RechargeTMallShop.Ctx(ctx).DB(config.GetDatabaseV1()).
Where(dao.V1RechargeTMallShop.Columns().TMallOrderNo, tMallOrderNo).Count()
err = utils.HandleNoRowsError(err)
return count > 0, err
}

View File

@@ -32,7 +32,9 @@ type (
Create(ctx context.Context, input *model.RechargeTMallGameOrderCreateInput) (orderNo string, err error)
// GetById 根据Id获取单个订单
GetById(ctx context.Context, orderNo string, tx gdb.TX) (data *entity.V1RechargeTMallOrder, err error)
// AssociateCreatedOrderAndStatus 关联相关订单
// GetByShopId 根据天猫订单关联查找对应订单
GetByShopId(ctx context.Context, shopOrderId int64, tx gdb.TX) (data *entity.V1RechargeTMallOrder, err error)
// AssociateCreatedOrderAndStatus 淘宝订单相互关联
AssociateCreatedOrderAndStatus(ctx context.Context, input *model.AssociateCreatedOrderAndStatusInput, tx gdb.TX) (err error)
// GetAllCreatedAccount 查询出所有正在创建状态的账号信息
GetAllCreatedAccount(ctx context.Context, tx gdb.TX) (data []model.RechargeTMallGameAccountOutput, err error)
@@ -42,6 +44,8 @@ type (
UpdateTMallCallBackInfo(ctx context.Context, input *model.UpdateAgisoCallBackInfoInput, tx gdb.TX) (err error)
// GetShopOne 获取订单详情
GetShopOne(ctx context.Context, shopOrderId int64) (res entity.V1RechargeTMallShop, err error)
// IsExist 判断当前订单是否存在
IsExist(ctx context.Context, tMallOrderNo int64) (bool, error)
// GetRecentOrdersByStatus 获取已经支付过的支付宝订单
GetRecentOrdersByStatus(ctx context.Context, status consts.RechargeTMallGameOrder, duration time.Duration, tx gdb.TX) (data []entity.V1RechargeTMallShop, err error)
// GetShopOrderByOrderNo 通过淘宝订单号获取淘宝订单信息

View File

@@ -8,7 +8,7 @@ package service
import (
"context"
"github.com/casbin/casbin/v2"
"github.com/casbin/casbin"
"github.com/casbin/casbin/v2/model"
)

View File

@@ -11,7 +11,7 @@ server:
errorLogPattern: "error-{Ymd}.log" # 异常错误日志文件格式默认为"error-{Ymd}.log"
accessLogEnabled: true # 是否记录访问日志默认为false
accessLogPattern: "access-{Ymd}.log" # 访问日志文件格式默认为"access-{Ymd}.log"
dumpRouterMap: false
dumpRouterMap: true
graceful: true # 是否开启平滑重启特性开启时将会在本地增加10000的本地TCP端口用于进程间通信默认false
gracefulTimeout: 2 # 父进程在平滑重启后多少秒退出默认2秒若请求耗时大于该值可能会导致请求中断
@@ -31,7 +31,7 @@ database:
Path: "resource/log/sql"
default:
link: "mysql:root:123456@tcp(myql:3306)/kami_v2?charset=utf8mb4&parseTime=true&loc=Local"
link: "mysql:root:123456@tcp(127.0.0.1:3306)/kami_v2?charset=utf8mb4&parseTime=true&loc=Local"
debug: false
charset: "utf8mb4" #数据库编码
dryRun: false #空跑
@@ -40,7 +40,7 @@ database:
maxLifetime: "30s" #(单位秒)连接对象可重复使用的时间长度
v1:
link: "mysql:root:123456@tcp(mysql:3306)/kami?charset=utf8mb4&parseTime=true&loc=Local"
link: "mysql:root:123456@tcp(127.0.0.1:3306)/kami?charset=utf8mb4&parseTime=true&loc=Local"
debug: true
charset: "utf8mb4" #数据库编码
dryRun: false #空跑
@@ -52,7 +52,7 @@ database:
redis:
# 单实例配置
default:
address: redis:6379
address: 127.0.0.1:6379
db: 4
idleTimeout: "60s" #连接最大空闲时间使用时间字符串例如30s/1m/1d
maxConnLifetime: "90s" #连接最长存活时间使用时间字符串例如30s/1m/1d

View File

@@ -11,7 +11,7 @@ server:
errorLogPattern: "error-{Ymd}.log" # 异常错误日志文件格式默认为"error-{Ymd}.log"
accessLogEnabled: true # 是否记录访问日志默认为false
accessLogPattern: "access-{Ymd}.log" # 访问日志文件格式默认为"access-{Ymd}.log"
dumpRouterMap: true
dumpRouterMap: false
graceful: true # 是否开启平滑重启特性开启时将会在本地增加10000的本地TCP端口用于进程间通信默认false
gracefulTimeout: 2 # 父进程在平滑重启后多少秒退出默认2秒若请求耗时大于该值可能会导致请求中断
@@ -31,7 +31,7 @@ database:
Path: "resource/log/sql"
default:
link: "mysql:root:123456@tcp(127.0.0.1:3306)/kami_v2?charset=utf8mb4&parseTime=true&loc=Local"
link: "mysql:root:123456@tcp(myql:3306)/kami_v2?charset=utf8mb4&parseTime=true&loc=Local"
debug: false
charset: "utf8mb4" #数据库编码
dryRun: false #空跑
@@ -40,7 +40,7 @@ database:
maxLifetime: "30s" #(单位秒)连接对象可重复使用的时间长度
v1:
link: "mysql:root:123456@tcp(127.0.0.1:3306)/kami?charset=utf8mb4&parseTime=true&loc=Local"
link: "mysql:root:123456@tcp(mysql:3306)/kami?charset=utf8mb4&parseTime=true&loc=Local"
debug: true
charset: "utf8mb4" #数据库编码
dryRun: false #空跑
@@ -52,7 +52,7 @@ database:
redis:
# 单实例配置
default:
address: 127.0.0.1:6379
address: redis:6379
db: 4
idleTimeout: "60s" #连接最大空闲时间使用时间字符串例如30s/1m/1d
maxConnLifetime: "90s" #连接最长存活时间使用时间字符串例如30s/1m/1d

View File

@@ -10,7 +10,6 @@ import (
func Register(ctx context.Context) {
//添加获取订单的定时任务
gtimer.AddSingleton(ctx, gtime.M, func(ctx2 context.Context) {
TMallOrderPaidStatus(ctx2)
TMallOrderDeliveryStatus(ctx2)
})
//添加获取订单的定时任务

View File

@@ -16,76 +16,8 @@ import (
"kami/utility/utils"
)
// TMallOrderPaidStatus 监控淘宝订单状态变化
func TMallOrderPaidStatus(ctx context.Context) {
//读取前30分钟的数据
glog.Info(ctx, "开始读取TMall订单状态")
rechargeTMallGameOrderService := service.RechargeTMallGameOrder()
tradeList, err := rechargeTMallGameOrderService.GetRecentOrdersByStatus(ctx, consts.RechargeTMallGameOrderStatusPaid, gtime.M*30, nil)
err = utils.HandleNoRowsError(err)
if err != nil || pointer.IsNil(tradeList) {
glog.Error(ctx, "读取内部存储淘宝订单列表错误:", err)
return
}
if len(tradeList) <= 0 {
return
}
tMallClient := tmallAPI.NewClient()
//读取最近最近的订单
tMallTradeList, err := tMallClient.GetTradeGetListByCreatedTime(ctx, tmall.ENUM_WAIT_SELLER_SEND_GOODS, gtime.M*30)
if err != nil {
glog.Error(ctx, "读取返回淘宝订单错误", err)
return
}
glog.Info(ctx, "读取淘宝订单列表:", tMallTradeList)
for _, tMallTrade := range tMallTradeList {
for _, order := range tradeList {
if gconv.Int64(tMallTrade.Tid) == order.TMallOrderNo {
// 获取详细订单
//更新订单状态
if err3 := config.GetDatabaseV1().Ctx(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
orderInfo, err2 := rechargeTMallGameOrderService.GetById(ctx, order.OrderNo, tx)
if err2 != nil {
glog.Error(ctx, "读取内部存储订单数据错误", err2)
return err2
}
//判断金额是不是相等
if orderInfo.Amount != orderInfo.Amount {
// 金额不符
err4 := rechargeTMallGameOrderService.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: order.OrderNo,
Status: consts.RechargeTMallGameOrderStatusFinishedWithWrongAmount,
}, tx)
glog.Error(ctx, "更新订单数据失败", err4)
return nil
}
glog.Info(ctx, "开始发货, 订单号:", order.TMallOrderNo)
if isSucceed, err3 := tMallClient.VirtualDelivery(ctx, order.TMallOrderNo); !isSucceed || err3 != nil {
glog.Error(ctx, "虚拟发货失败", err3)
err4 := rechargeTMallGameOrderService.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: order.OrderNo,
Status: consts.RechargeTMallGameOrderStatusDeliverySucceed,
}, tx)
glog.Error(ctx, "更新订单数据失败", err4)
} else {
err4 := rechargeTMallGameOrderService.UpdateOrderStatusByTBOrderNo(ctx, &model.UpdateOrderStatusByTBOrderNoInput{
OrderNo: order.OrderNo,
Status: consts.RechargeTMallGameOrderStatusDeliveryFailed,
}, tx)
glog.Error(ctx, "更新订单数据失败", err4)
}
return nil
}); err3 != nil {
glog.Error(ctx, "更新订单数据失败", err)
}
}
}
}
}
func TMallOrderDeliveryStatus(ctx context.Context) {
//读取前30分钟的数据
glog.Info(ctx, "开始读取TMall完成订单状态")
rechargeTMallGameOrderService := service.RechargeTMallGameOrder()
tradeList, err := rechargeTMallGameOrderService.GetRecentOrdersByStatus(ctx, consts.RechargeTMallGameOrderStatusDeliverySucceed, gtime.D, nil)
err = utils.HandleNoRowsError(err)