123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 |
- package jobs
- import (
- "context"
- "errors"
- "gadmin/config"
- "gadmin/internal/admin/consts"
- "gadmin/internal/gorm/model"
- "gadmin/internal/gorm/query"
- "gadmin/utility/player"
- "github.com/jinzhu/now"
- "github.com/sirupsen/logrus"
- "gorm.io/gorm"
- "gorm.io/gorm/clause"
- "os"
- "sync"
- "time"
- )
- var SyncOrders = new(jSyncOrders)
- const DelaySecond = 7200 // 延迟拉取2小時内的订单,防止订单未支付而过后又支付完成的情况 (ios)
- const DelayId = 50 // 延迟拉取前N个订单,防止订单未支付而过后又支付完成的情况 (安卓)
- type jSyncOrders struct {
- sync.Mutex
- }
- // Run
- // 存在问题:
- // 1. 通过尾数U...关联时,如果存在多个相同的关联,无法准备识别应该关联哪个
- // 2. 有个别是U无法准确关联 绝大部分是U+1
- // 3. 过早的订单存在直接无法关联问题
- func (j *jSyncOrders) Run() {
- logrus.Info("SyncOrders Run.....")
- if os.Getenv("GIN_MODE") != "release" && os.Getenv("ADMIN_IS_LOCAL") != "1" {
- logrus.Warnf("测试环境禁止同步")
- return
- }
- j.Lock()
- defer j.Unlock()
- //游戏服订单相关表
- //virtualpayorder表示游戏内订单 InGameOrders
- //wxpay_iosorder表示游戏外订单 OutOfGameOrders
- //wxpay_order存储订单状态
- for serverId, _ := range config.GDBGroup {
- j.syncInGameOrders(serverId)
- j.syncOutOfGameOrders(serverId)
- }
- //for serverId, _ := range config.GDBGroup {
- // j.syncIos(serverId)
- // j.syncAndroid(serverId)
- //}
- }
- func (j *jSyncOrders) syncInGameOrders(serverId int) {
- logrus.Infof("Load Sync In-Game-Orders; ServerId %d .....", serverId)
- //获取游戏服id
- DB, err := player.GetDBByServerID(serverId)
- if err != nil {
- logrus.Warningf("syncAndroid GetDBByServerID,err:%v", err)
- return
- }
- //PayOrderAndriod 原名virtualpayorder 表示游戏内订单
- //PayOrderIos 原名wxpay_iosorder 表示游戏外订单
- var (
- ctx = context.TODO()
- o = query.Use(config.GDBGroup[DB]).PayOrderAndriod
- m = o.WithContext(ctx)
- orderList []model.PayOrderAndriod
- lastOrder model.Order
- )
- //获取游戏内最后一笔订单时间/id
- lastOrderSyncInfo, err := j.getLastOrderIdByOrderWay(serverId, consts.InGameOrders)
- if err != nil {
- logrus.Warnf("getLastOrderTime err . %v", err)
- return
- }
- //获取近两个小时内的订单
- if lastOrderSyncInfo.ID != 0 {
- m = m.Where(o.CreateTime.Gte(lastOrderSyncInfo.LastCreateTime.Add(time.Hour * -2)))
- }
- if err = m.Scan(&orderList); err != nil {
- logrus.Warnf("orderList Scan err . %v", err)
- return
- }
- if len(orderList) == 0 {
- logrus.Warnf("没有需要同步的订单")
- return
- }
- uIds := make([]int64, 0)
- uIdsMap := make(map[int64]struct{})
- for _, order := range orderList {
- if _, ok := uIdsMap[order.Playerid]; ok {
- continue
- }
- uIdsMap[order.Playerid] = struct{}{}
- uIds = append(uIds, order.Playerid)
- }
- firstOrders, err := o.WithContext(ctx).Select(o.Playerid).Group(o.Playerid).Where(o.Playerid.In(uIds...)).Having(o.Playerid.Count().Eq(1)).Find()
- if err != nil {
- return
- }
- newOrder := make(map[int64]struct{})
- for _, order := range firstOrders {
- newOrder[order.ID] = struct{}{}
- }
- for _, order := range orderList {
- var (
- isNew int32 = 0
- status int32 = consts.OrderStatusNo
- orderSn = ""
- goodsID = int32(order.GoodsID)
- orderDate = ""
- payAt time.Time
- createdAt time.Time
- )
- if _, ok := newOrder[order.ID]; ok {
- isNew = 1
- }
- status = consts.OrderStateSuccess
- payAt = order.CreateTime
- orderDate = payAt.Format("2006-01-02")
- createdAt = payAt
- if payAt.IsZero() {
- payAt = time.Now().In(time.Local)
- }
- channelID := player.GetUserChannel(order.Playerid)
- userCreatedAt := player.GetUserStamp(order.Playerid)
- paymentType := consts.OrderPaymentType
- if order.Platform == 1 {
- paymentType = consts.OrderPaymentTypeWx
- } else if order.Platform == 2 {
- paymentType = consts.OrderPaymentTypeDy
- }
- platform := consts.OrderPlatform
- // 0:苹果游戏外微信支付 1:安卓游戏内支付 2:安卓游戏外微信支付 3:苹果游戏内支付
- if order.PayMethod == 3 {
- platform = consts.OrderPlatformIos
- } else if order.PayMethod == 1 || order.PayMethod == 2 {
- platform = consts.OrderPlatformAndroid
- }
- lastOrder = model.Order{
- ServerID: int32(serverId),
- Platform: int32(platform),
- PaymentType: int32(paymentType),
- RelatID: int32(order.ID),
- PlayerID: order.Playerid,
- GoodsID: goodsID,
- OrderSn: orderSn,
- OutTradeNo: order.BillNo,
- Money: float64(order.Balance-order.PayedBalance) / 100,
- IsNew: isNew,
- Status: status,
- Date: orderDate,
- PayAt: payAt,
- CreatedAt: createdAt,
- ChannelID: channelID,
- UserCreatedAt: userCreatedAt,
- Flag: player.GetUserFlag(serverId, order.Playerid),
- }
- if err = j.saveOrder(lastOrder); err != nil {
- logrus.Warnf("Android saveOrder Scan err: %v; order:%+v; lastOrder:%+v;\n", err, order, lastOrder)
- return
- }
- }
- if err = j.setLastOrderTime(serverId, lastOrder, consts.InGameOrders, lastOrderSyncInfo.ID); err != nil {
- logrus.Warnf("setLastOrderTime Scan err . %v", err)
- return
- }
- }
- func (j *jSyncOrders) syncOutOfGameOrders(serverId int) {
- logrus.Infof("Load Sync Out-Of-Game-Orders; ServerId: %d .....", serverId)
- lastOrderSyncInfo, err := j.getLastOrderIdByOrderWay(serverId, consts.OutOfGameOrders)
- if err != nil {
- logrus.Warnf("getLastOrderTime err . %v", err)
- return
- }
- DB, err := player.GetDBByServerID(serverId)
- if err != nil {
- logrus.Warningf("syncIos GetDBByServerID,err:%v", err)
- return
- }
- var (
- ctx = context.TODO()
- o = query.Use(config.GDBGroup[DB]).PayOrderIos
- m = o.WithContext(ctx)
- orderList []model.PayOrderIos
- lastOrder model.Order
- )
- //获取近两个小时内的订单
- if lastOrderSyncInfo.ID != 0 {
- m = m.Where(o.CreateTime.Gte(lastOrderSyncInfo.LastCreateTime.Add(time.Hour * -2)))
- }
- if err = m.Scan(&orderList); err != nil {
- logrus.Warnf("orderList Scan err . %v", err)
- return
- }
- if len(orderList) == 0 {
- logrus.Warnf("没有需要同步的订单")
- return
- }
- uIds := make([]int64, 0)
- uIdsMap := make(map[int64]struct{})
- for _, order := range orderList {
- if _, ok := uIdsMap[order.PlayerID]; ok {
- continue
- }
- uIdsMap[order.PlayerID] = struct{}{}
- uIds = append(uIds, order.PlayerID)
- }
- //查找第一次下单的用户
- newOrders := make(map[int64]struct{})
- firstOrders, err := o.WithContext(ctx).Select(o.PlayerID).Group(o.PlayerID).Where(o.PlayerID.In(uIds...)).Having(o.PlayerID.Count().Eq(1)).Find()
- if err != nil {
- return
- }
- for _, order := range firstOrders {
- newOrders[order.PlayerID] = struct{}{}
- }
- for _, order := range orderList {
- var (
- isNew int32 = 0
- )
- if _, ok := newOrders[order.PlayerID]; ok {
- isNew = 1
- }
- PayAt := time.Unix(0, 0).In(time.Local)
- if order.SuccessTime != "" {
- PayAt, _ = now.ParseInLocation(time.Local, order.SuccessTime)
- }
- if order.TradeState != "SUCESS" {
- continue
- }
- channelID := player.GetUserChannel(order.PlayerID)
- userCreatedAt := player.GetUserStamp(order.PlayerID)
- paymentType := consts.OrderPaymentType
- if order.Platform == 1 {
- paymentType = consts.OrderPaymentTypeWx
- } else if order.Platform == 2 {
- paymentType = consts.OrderPaymentTypeDy
- }
- platform := consts.OrderPlatform
- //order.Phone 1苹果 2安卓
- if order.Phone == 1 {
- platform = consts.OrderPlatformIos
- } else if order.Phone == 2 {
- platform = consts.OrderPlatformAndroid
- }
- lastOrder = model.Order{
- ServerID: int32(serverId),
- Platform: int32(platform),
- RelatID: int32(order.ID),
- PaymentType: int32(paymentType),
- PlayerID: order.PlayerID,
- GoodsID: order.GoodsID,
- OrderSn: order.OutTradeNo,
- OutTradeNo: order.TransactionID,
- Money: float64(order.Total) / 100,
- IsNew: isNew,
- Status: consts.OrderStatusSuccess,
- Date: order.CreateTime.Format("2006-01-02"),
- PayAt: PayAt,
- CreatedAt: order.CreateTime,
- ChannelID: channelID,
- UserCreatedAt: userCreatedAt,
- Flag: player.GetUserFlag(serverId, order.PlayerID),
- }
- if err = j.saveOrder(lastOrder); err != nil {
- logrus.Warnf("IOS saveOrder Scan err: %v; order:%+v; lastOrder:%+v;\n", err, order, lastOrder)
- return
- }
- }
- if err = j.setLastOrderTime(serverId, lastOrder, consts.OutOfGameOrders, lastOrderSyncInfo.ID); err != nil {
- logrus.Warnf("setLastOrderTime Scan err . %v", err)
- return
- }
- }
- //func (j *jSyncOrders) syncAndroid(serverId int) {
- // logrus.Info("load SyncAndroid .....")
- // lastId, err := j.getLastOrderId(serverId, consts.OrderPlatformAndroid)
- // if err != nil {
- // logrus.Warnf("getLastOrderTime err . %v", err)
- // return
- // }
- //
- // DB, err := player.GetDBByServerID(serverId)
- // if err != nil {
- // logrus.Warningf("syncAndroid GetDBByServerID,err:%v", err)
- // return
- // }
- //
- // var (
- // o = query.Use(config.GDBGroup[DB]).PayOrderAndriod
- // m = o.WithContext(context.TODO())
- // orderLst []model.PayOrderAndriod
- // lastOrder model.Order
- // )
- //
- // if lastId > 0 {
- // m = m.Where(o.ID.Gte(lastId))
- // }
- //
- // if err = m.Scan(&orderLst); err != nil {
- // logrus.Warnf("orderLst Scan err . %v", err)
- // return
- // }
- //
- // if len(orderLst) == 0 {
- // logrus.Warnf("没有需要同步的订单")
- // return
- // }
- //
- // for _, order := range orderLst {
- // var (
- // isNew int32 = 0
- // status int32 = consts.OrderStatusNo
- // dao = query.Use(config.GDBGroup[DB]).PayOrderAndriod
- // orderSn = ""
- // goodsID = int32(order.GoodsID)
- // orderDate = ""
- // payAt time.Time
- // createdAt time.Time
- // )
- //
- // first, err := dao.Where(dao.Playerid.Eq(order.Playerid)).First()
- // if err == nil && first != nil {
- // if first.ID == order.ID {
- // isNew = 1
- // }
- // }
- //
- // status = consts.OrderStateSuccess
- //
- // payAt = order.CreateTime
- // orderDate = payAt.Format("2006-01-02")
- // createdAt = payAt
- //
- // if payAt.IsZero() {
- // payAt = time.Now().In(time.Local)
- // }
- //
- // channelID := player.GetUserChannel(order.Playerid)
- // userCreatedAt := player.GetUserStamp(order.Playerid)
- //
- // lastOrder = model.Order{
- // ServerID: int32(serverId),
- // Platform: consts.OrderPlatformAndroid,
- // RelatID: int32(order.ID),
- // PaymentType: consts.OrderPaymentTypeWx,
- // PlayerID: order.Playerid,
- // GoodsID: goodsID,
- // OrderSn: orderSn,
- // OutTradeNo: order.BillNo,
- // Money: float64(order.Balance-order.PayedBalance) / 100,
- // IsNew: isNew,
- // Status: status,
- // Date: orderDate,
- // PayAt: payAt,
- // CreatedAt: createdAt,
- // ChannelID: channelID,
- // UserCreatedAt: userCreatedAt,
- // Flag: player.GetUserFlag(serverId, order.Playerid),
- // }
- //
- // if err = j.saveOrder(lastOrder); err != nil {
- // logrus.Warnf("Android saveOrder Scan err: %v; order:%+v; lastOrder:%+v;\n", err, order, lastOrder)
- // return
- // }
- // }
- //
- // if err = j.setLastOrderTime(serverId, consts.OrderPlatformAndroid, lastOrder); err != nil {
- // logrus.Warnf("setLastOrderTime Scan err . %v", err)
- // return
- // }
- //}
- //
- //func (j *jSyncOrders) syncIos(serverId int) {
- // logrus.Info("load SyncIos .....")
- // lastTime, err := j.getLastOrderTime(serverId, consts.OrderPlatformIos)
- // if err != nil {
- // logrus.Warnf("getLastOrderTime err . %v", err)
- // return
- // }
- //
- // DB, err := player.GetDBByServerID(serverId)
- // if err != nil {
- // logrus.Warningf("syncIos GetDBByServerID,err:%v", err)
- // return
- // }
- //
- // var (
- // o = query.Use(config.GDBGroup[DB]).PayOrderIos
- // m = o.WithContext(context.TODO())
- // orderLst []model.PayOrderIos
- // lastOrder model.Order
- // )
- //
- // if lastTime.Unix() > 0 {
- // m = m.Where(o.CreateTime.Gte(lastTime.Add(-time.Second * DelaySecond)))
- // }
- //
- // if err = m.Scan(&orderLst); err != nil {
- // logrus.Warnf("orderLst Scan err . %v", err)
- // return
- // }
- //
- // if len(orderLst) == 0 {
- // logrus.Warnf("没有需要同步的订单")
- // return
- // }
- //
- // for _, order := range orderLst {
- // var (
- // isNew int32 = 0
- // status int32 = consts.OrderStatusNo
- // dao = query.Use(config.GDBGroup[DB]).PayOrderIos
- // )
- //
- // first, err := query.Use(config.GDBGroup[DB]).PayOrderIos.Select(dao.ALL).Where(dao.TradeState.Eq("SUCESS"), dao.PlayerID.Eq(order.PlayerID)).First()
- // if err == nil && first != nil {
- // if first.ID == order.ID {
- // isNew = 1
- // }
- // }
- //
- // payAt, err := now.ParseInLocation(time.Local, order.SuccessTime)
- // if err != nil {
- // payAt = time.Now().In(time.Local)
- // logrus.Errorf("order successtime parse err: %v; payAt: %v;\n", err, payAt)
- // }
- //
- // if order.TradeState == "SUCESS" {
- // status = consts.OrderStatusSuccess
- // } else if order.TradeState == "CLOSED" {
- // status = consts.OrderStatusCancel
- // } else if order.TradeState == "NOTENOUGH" {
- // status = consts.OrderStatusNotEnough
- // } else {
- // status = consts.OrderStatusOther
- // }
- //
- // channelID := player.GetUserChannel(order.PlayerID)
- // userCreatedAt := player.GetUserStamp(order.PlayerID)
- //
- // lastOrder = model.Order{
- // ServerID: int32(serverId),
- // Platform: consts.OrderPlatformIos,
- // RelatID: int32(order.ID),
- // PaymentType: consts.OrderPaymentTypeWx,
- // PlayerID: order.PlayerID,
- // GoodsID: order.GoodsID,
- // OrderSn: order.OutTradeNo,
- // OutTradeNo: order.TransactionID,
- // Money: float64(order.Total) / 100,
- // IsNew: isNew,
- // Status: status,
- // Date: order.CreateTime.Format("2006-01-02"),
- // PayAt: payAt,
- // CreatedAt: order.CreateTime,
- // ChannelID: channelID,
- // UserCreatedAt: userCreatedAt,
- // Flag: player.GetUserFlag(serverId, order.PlayerID),
- // }
- //
- // if err = j.saveOrder(lastOrder); err != nil {
- // logrus.Warnf("IOS saveOrder Scan err: %v; order:%+v; lastOrder:%+v;\n", err, order, lastOrder)
- // return
- // }
- // }
- //
- // if err = j.setLastOrderTime(serverId, consts.OrderPlatformIos, lastOrder); err != nil {
- // logrus.Warnf("setLastOrderTime Scan err . %v", err)
- // return
- // }
- //}
- // getLastOrderTime 获取下次同步订单的截止时间,主要用于ios
- func (j *jSyncOrders) getLastOrderTime(serverId int, platform int32) (last time.Time, err error) {
- var (
- q = query.Use(config.DB).OrdersSync
- models model.OrdersSync
- )
- if err = q.Where(q.Platform.Eq(platform), q.ServerID.Eq(int32(serverId))).Scan(&models); err != nil {
- return
- }
- return models.LastCreateTime, nil
- }
- // getLastOrderTime 获取下次同步订单的截止ID,主要用于安卓
- func (j *jSyncOrders) getLastOrderId(serverId int, platform int32) (last int64, err error) {
- var (
- q = query.Use(config.DB).OrdersSync
- models model.OrdersSync
- )
- if err = q.Where(q.Platform.Eq(platform), q.ServerID.Eq(int32(serverId))).Scan(&models); err != nil {
- return
- }
- if models.LastID == 0 {
- return 0, nil
- }
- return models.LastID - DelayId, nil
- }
- func (j *jSyncOrders) getLastOrderIdByOrderWay(serverId int, orderWay int) (lastOrder *model.OrdersSync, err error) {
- var (
- q = query.Use(config.DB).OrdersSync
- )
- res, err := q.Where(q.ServerID.Eq(int32(serverId)), q.OrderWay.Eq(int32(orderWay))).First()
- if err != nil {
- if errors.Is(err, gorm.ErrRecordNotFound) {
- return &model.OrdersSync{}, nil
- }
- return
- }
- return res, nil
- }
- func (j *jSyncOrders) setLastOrderTime(serverId int, data model.Order, orderWay int, lastSyncInfoId int64) (err error) {
- var (
- q = query.Use(config.DB).OrdersSync
- )
- syncData := &model.OrdersSync{
- LastID: int64(data.RelatID),
- LastCreateTime: data.CreatedAt,
- UpdatedAt: time.Now(),
- }
- if lastSyncInfoId != 0 {
- _, err := q.Where(q.ID.Eq(lastSyncInfoId)).Updates(syncData)
- if err != nil {
- return err
- }
- } else {
- syncData.ServerID = int32(serverId)
- syncData.OrderWay = int32(orderWay)
- err := q.Create(syncData)
- if err != nil {
- return err
- }
- }
- return
- }
- func (j *jSyncOrders) saveOrder(data model.Order) (err error) {
- //var (
- // q = query.Use(config.DB).Order
- // models model.Order
- //)
- //
- //if err = q.Where(q.ServerID.Eq(data.ServerID), q.RelatID.Eq(data.RelatID), q.Platform.Eq(data.Platform)).Scan(&models); err != nil {
- // return err
- //}
- //
- //if models.ID > 0 {
- // if _, err = query.Use(config.DB).Order.Where(q.RelatID.Eq(data.RelatID), q.Platform.Eq(data.Platform)).Updates(&data); err != nil {
- // return err
- // }
- // return nil
- //} else {
- // return query.Use(config.DB).Order.Create(&data)
- //}
- return query.Use(config.DB).Order.Clauses(clause.OnConflict{UpdateAll: true}).Create(&data)
- }
|