Browse Source

重新设置支付方式

master
黄梓健 5 years ago
parent
commit
aa1095b99e
  1. 2
      controllers/client/bully_screen.go
  2. 190
      controllers/client/live.go
  3. 8
      controllers/client/reward.go
  4. 27
      controllers/common/wechat_oauth.go
  5. 27
      controllers/pc/bully_screen.go
  6. 34
      controllers/pc/reward.go
  7. 1
      go.mod
  8. 9
      libs/im/im.go
  9. 2
      log/hdzj.log
  10. 26
      models/bully_screen_history.go
  11. 1
      models/init_models.go
  12. 2
      models/live_red_pack.go
  13. 3
      models/live_red_pack_info.go
  14. 16
      models/reward_history.go
  15. 24
      models/user_order.go
  16. 53
      models/user_transfer.go
  17. 140
      services/bully_reward/dao.go
  18. 19
      services/im/im.go
  19. 4
      services/pay/const.go
  20. 224
      services/pay/order.go
  21. 32
      services/pay/refund.go
  22. 163
      services/pay/transfer.go
  23. 26
      test/pay_test.go

2
controllers/client/bully_screen.go

@ -54,7 +54,7 @@ func (t *BullyScreenCtl) PaScreen() {
// 调用微信统一下单接口 // 调用微信统一下单接口
amount := bullyScreenServer.Price * second amount := bullyScreenServer.Price * second
ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":") ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":")
res, err := pay_service.Order("欧轩互动-霸屏支付", ip[0], user.Openid, int64(amount*100), 1, user.Id, activityId)
res, err := pay_service.UnifiedOrder("欧轩互动-霸屏支付", ip[0], user.Openid, int64(amount*100), 1, user.Id, activityId)
t.CheckErr(err) t.CheckErr(err)
history := &models.BullyScreenHistory{ history := &models.BullyScreenHistory{

190
controllers/client/live.go

@ -6,102 +6,50 @@ import (
"hudongzhuanjia/libs/filter" "hudongzhuanjia/libs/filter"
"hudongzhuanjia/logger" "hudongzhuanjia/logger"
"hudongzhuanjia/models" "hudongzhuanjia/models"
im_service "hudongzhuanjia/services/im"
pay_service "hudongzhuanjia/services/pay" pay_service "hudongzhuanjia/services/pay"
red_envelope_service "hudongzhuanjia/services/red_envelope" red_envelope_service "hudongzhuanjia/services/red_envelope"
"hudongzhuanjia/utils" "hudongzhuanjia/utils"
"hudongzhuanjia/utils/code" "hudongzhuanjia/utils/code"
"math"
"strings" "strings"
"time" "time"
) )
var MaxQueueSize = 10000
var RequestLimit = 60 * time.Second
var GetRedPackQueue = make(chan string, MaxQueueSize)
func loopGetRedPack() {
redPacks, err := models.GetRedPacksByStatus(1)
if err != nil {
panic(err)
}
// 保证容量足够
GetRedPackQueue = make(chan string, MaxQueueSize+len(redPacks))
// 初始化
for _, redPack := range redPacks {
GetRedPackQueue <- redPack.TransferNo
}
defer func() {
if errRec := recover(); errRec != nil {
logger.Error("用户转账轮询发生错误",
zap.String("函数", "loopGetRedPack"), zap.Any("错误原因", errRec))
}
time.Sleep(5 * time.Second)
loopGetRedPack()
}()
for {
select {
case transferNo, ok := <-GetRedPackQueue:
if !ok {
panic("GetRedPackQueue通道关闭")
}
time.Sleep(RequestLimit) // 请求频率
type NoticeRedPackEvent struct {
OutTradeNo string `json:"out_trade_no"`
Prompt string `json:"prompt"`
RedPackInfoId int64 `json:"red_pack_info_id"`
ActivityId int64 `json:"activity_id"`
Status int `json:"status"`
}
redPack := new(models.LiveRedPack)
exist, err := redPack.GetByTransferNo(transferNo)
if err != nil || !exist {
logger.Error("获取LiveRedPack表数据出现错误", zap.String("错误原因", err.Error()),
zap.Bool("是否存在", exist), zap.Int64("LiveRedPack表的id", redPack.Id))
continue
}
var SendRedPackQueue = make(chan *NoticeRedPackEvent, math.MaxInt8)
// todo: 增加一个查询机制 --查询此次付款是否成功
// todo: 是否需要发放系统通知
resp, err := pay_service.TransferInfo(redPack.TransferNo)
if err != nil {
GetRedPackQueue <- transferNo
logger.Error("微信企业转账查询API",
zap.Any("错误原因", err), zap.Int64("LiveRedPack表的id", redPack.Id))
continue
}
if resp.Status == pay_service.CODE_FAIL { // 转账失败
_, err = pay_service.Transfer("欧轩互动-红包活动", redPack.OpenId, redPack.TransferNo, redPack.Amount)
if err != nil {
GetRedPackQueue <- transferNo
logger.Error("微信企业转账API",
zap.String("错误原因", err.Error()), zap.String("转账单号", transferNo))
continue
}
_, err = redPack.UpdateStatusById(redPack.Id, 2)
if err != nil {
GetRedPackQueue <- transferNo
logger.Error("微信企业转账API,LiveRedPack表更新错误",
zap.String("错误原因", err.Error()), zap.String("转账单号", transferNo))
continue
}
} else if resp.Status == pay_service.CODE_SUCCESS {
_, err = redPack.UpdateStatusById(redPack.Id, 2)
if err != nil {
logger.Error("微信企业查询,转账成功",
zap.String("错误原因", err.Error()), zap.String("转账单号", transferNo))
continue
}
}
}
func PutSendRedPackQueue(outTradeNo, prompt string, redPackInfoId, activityId int64, status int) {
SendRedPackQueue <- &NoticeRedPackEvent{
OutTradeNo: outTradeNo,
Prompt: prompt,
RedPackInfoId: redPackInfoId,
ActivityId: activityId,
Status: status,
} }
} }
var SendRedPackQueue = make(chan string)
func loopSendRedPack() { func loopSendRedPack() {
redPackInfos, err := models.GetLiveRedPackInfos(0) redPackInfos, err := models.GetLiveRedPackInfos(0)
if err != nil { if err != nil {
panic(err) panic(err)
} }
SendRedPackQueue = make(chan string, MaxQueueSize+len(redPackInfos))
SendRedPackQueue = make(chan *NoticeRedPackEvent, math.MaxInt8)
for _, redPackInfo := range redPackInfos { for _, redPackInfo := range redPackInfos {
SendRedPackQueue <- redPackInfo.OutTradeNo
SendRedPackQueue <- &NoticeRedPackEvent{
OutTradeNo: redPackInfo.OutTradeNo,
Prompt: redPackInfo.Prompt,
RedPackInfoId: redPackInfo.Id,
ActivityId: redPackInfo.ActivityId,
Status: redPackInfo.Status,
}
} }
defer func() { defer func() {
@ -112,47 +60,56 @@ func loopSendRedPack() {
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
loopSendRedPack() loopSendRedPack()
}() }()
for { for {
select { select {
case outTradeNo, ok := <-SendRedPackQueue:
case param, ok := <-SendRedPackQueue:
if !ok { if !ok {
panic("SendRedPackQueue通道异常关闭") panic("SendRedPackQueue通道异常关闭")
} }
redPackInfo := new(models.LiveRedPackInfo)
exist, err := redPackInfo.GetByOutTradeNo(outTradeNo)
if param.Status != 0 && param.Status != 1 { // 已推送和已作废过滤掉
continue
}
userOrder := new(models.UserOrder)
exist, err := userOrder.GetByOutTradeNo(param.OutTradeNo)
if err != nil || !exist { if err != nil || !exist {
logger.Error("通过out_trade_no获取red_pack_info", zap.String("错误原因", err.Error()),
zap.Bool("是否存在", exist), zap.String("交易单号", outTradeNo))
logger.Error("通过out_trade_no获取user_order订单信息", zap.String("错误原因", err.Error()),
zap.Bool("是否存在", exist), zap.String("交易单号", param.OutTradeNo))
continue continue
} }
res, err := pay_service.OrderQuery(outTradeNo)
if err != nil {
SendRedPackQueue <- outTradeNo
logger.Error("微信查询订单API", zap.String("错误原因", err.Error()),
zap.String("交易单号", outTradeNo))
if userOrder.Status == 0 { // NOPAY
SendRedPackQueue <- param
continue
} else if userOrder.Status == 1 {
param.Status = 1
} else {
param.Status = 2 // 作废订单
} }
if res.TradeState == pay_service.CODE_TRADE_SUCCESS { // 交易成功
redPackInfo.Status = 1
} else if res.TradeState == pay_service.CODE_TRADE_CLOSED {
redPackInfo.Status = 3
} else if res.TradeState == pay_service.CODE_TRADE_PAYERROR { // 支付失败
redPackInfo.Status = 4
} else if res.TradeState == pay_service.CODE_TRADE_NOTPAY {
time.Sleep(5 * time.Second)
SendRedPackQueue <- outTradeNo
err = im_service.SendNoticeByActivityId(param.ActivityId, map[string]interface{}{
"prompt": param.Prompt,
"timestamp": time.Now().Unix(),
"red_pack_info_id": param.RedPackInfoId,
})
if err != nil {
logger.Error("red_pack_info推送通知出现错误", zap.String("错误原因", err.Error()),
zap.String("交易单号", param.Prompt))
continue continue
} }
_, err = redPackInfo.UpdateStatusById(redPackInfo.Id, redPackInfo.Status)
_, err = new(models.LiveRedPackInfo).UpdateStatusByOutTradeNo(param.OutTradeNo, param.Status)
if err != nil { if err != nil {
logger.Error("red_pack_info状态更新出现错误", zap.String("错误原因", err.Error()), logger.Error("red_pack_info状态更新出现错误", zap.String("错误原因", err.Error()),
zap.String("交易单号", outTradeNo))
zap.String("交易单号", param.OutTradeNo))
continue
} }
} }
} }
} }
func init() { func init() {
go loopGetRedPack()
go loopSendRedPack() go loopSendRedPack()
} }
@ -215,7 +172,7 @@ func (t *LiveCtl) LoopQuery() {
}) })
} }
// 发送红包
// 下单发送红包
// 维护一个队列进行循环, 遍历是否付款成功 // 维护一个队列进行循环, 遍历是否付款成功
func (t *LiveCtl) SendLiveRedPack() { func (t *LiveCtl) SendLiveRedPack() {
userId := t.MustGetUID() // 用户 uid userId := t.MustGetUID() // 用户 uid
@ -230,7 +187,7 @@ func (t *LiveCtl) SendLiveRedPack() {
t.Assert(exist, code.MSG_USER_NOT_EXIST, "用户不存在") t.Assert(exist, code.MSG_USER_NOT_EXIST, "用户不存在")
ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":") ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":")
res, err := pay_service.Order("欧轩互动-直播红包", ip[0], user.Openid, amount, 3, activityId, userId)
res, err := pay_service.UnifiedOrder("欧轩互动-直播红包", ip[0], user.Openid, amount, 3, activityId, userId)
t.CheckErr(err) t.CheckErr(err)
info := models.LiveRedPackInfo{} info := models.LiveRedPackInfo{}
@ -259,11 +216,34 @@ func (t *LiveCtl) SendLiveRedPack() {
} }
res["red_pack_info_id"] = info.Id res["red_pack_info_id"] = info.Id
pay_service.PutOrderChan(info.OutTradeNo) // 加入查询队列
go PutSendRedPackQueue(info.OutTradeNo, info.Prompt, info.Id, info.ActivityId, info.Status) // 加入发送队列
t.JSON(res) t.JSON(res)
} }
// 支付之后可以遍历查询是否成功 -- 前端发送消息
func (t *LiveCtl) QueryRedPack() {
outTradeNo := t.MustGet("out_trade_no")
res, err := pay_service.OrderQuery(outTradeNo)
t.CheckErr(err)
info := new(models.LiveRedPackInfo)
exist, err := info.GetByOutTradeNo(outTradeNo)
t.CheckErr(err)
t.Assert(exist, code.MSG_LIVE_RED_PACK_NOT_EXIST, "直播红包信息不存在")
if res.TradeState == pay_service.CODE_TRADE_SUCCESS {
info.Status = 1
info.UpdateStatusById(info.Id, info.Status)
t.JSON(map[string]interface{}{
"red_pack_info_id": info.Id,
"status": info.Status,
})
} else {
t.JSON(map[string]interface{}{
"red_pack_info_id": info.Id,
"status": info.Status,
})
}
}
// 领取红包 // 领取红包
func (t *LiveCtl) GetRedPack() { func (t *LiveCtl) GetRedPack() {
liveRedPackInfoId := t.MustGetInt64("live_red_pack_info_id") liveRedPackInfoId := t.MustGetInt64("live_red_pack_info_id")
@ -287,14 +267,14 @@ func (t *LiveCtl) GetRedPack() {
redPack.OpenId = user.Openid redPack.OpenId = user.Openid
redPack.Receiver = user.Id redPack.Receiver = user.Id
redPack.TransferType = 1 redPack.TransferType = 1
redPack.TransferNo = utils.RandomStr(32)
redPack.PartnerTradeNo = utils.RandomStr(32)
row, err := redPack.UpdateStatusById(redPack.Id, 1) row, err := redPack.UpdateStatusById(redPack.Id, 1)
t.CheckErr(err) t.CheckErr(err)
if row != 1 { if row != 1 {
t.ERROR("红包被领完了", code.MSG_LIVE_RED_PACK_NOT_EXIST) t.ERROR("红包被领完了", code.MSG_LIVE_RED_PACK_NOT_EXIST)
return return
} }
GetRedPackQueue <- redPack.TransferNo // 进入队列
pay_service.PutTransferDelayQueue("欧轩互动-红包活动", user.Openid, redPack.PartnerTradeNo, redPack.Amount, 5, 5*60)
t.JSON(redPack) t.JSON(redPack)
} }

8
controllers/client/reward.go

@ -27,10 +27,12 @@ func (t *RewardCtl) Reward() {
if amount <= 0 { if amount <= 0 {
t.ERROR("打赏金额不能小于0", code.MSG_ERR_Param) t.ERROR("打赏金额不能小于0", code.MSG_ERR_Param)
return
} }
//检查内容是否包含敏感 //检查内容是否包含敏感
if ok, _ := filter.Validate(content); !ok { if ok, _ := filter.Validate(content); !ok {
t.ERROR("内容包含敏感字", code.MSG_ERR) t.ERROR("内容包含敏感字", code.MSG_ERR)
return
} }
activity := new(models.Activity) activity := new(models.Activity)
@ -52,7 +54,7 @@ func (t *RewardCtl) Reward() {
t.Assert(exist, code.MSG_USER_NOT_EXIST, "用户不存在") t.Assert(exist, code.MSG_USER_NOT_EXIST, "用户不存在")
ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":") ip := strings.Split(t.Request.OriginRequest.RemoteAddr, ":")
res, err := pay_service.Order("欧轩互动-打赏支付", ip[0], user.Openid, int64(amount*100), 2, user.Id, activityId)
res, err := pay_service.UnifiedOrder("欧轩互动-打赏支付", ip[0], user.Openid, int64(amount*100), 2, user.Id, activityId)
t.CheckErr(err) t.CheckErr(err)
_, err = core.GetXormAuto().InsertOne(&models.RewardHistory{ _, err = core.GetXormAuto().InsertOne(&models.RewardHistory{
@ -70,6 +72,7 @@ func (t *RewardCtl) Reward() {
UpdatedAt: time.Now(), UpdatedAt: time.Now(),
}) })
t.CheckErr(err) t.CheckErr(err)
t.JSON(res) t.JSON(res)
} }
@ -82,6 +85,9 @@ func (t *RewardCtl) List() {
t.CheckErr(err) t.CheckErr(err)
t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在") t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在")
// todo: 检查订单
t.CheckErr(bully_reward_service.CheckRewardStatus(rs.Id))
list, err := bully_reward_service.GetRewardList(uid, rs.Id) list, err := bully_reward_service.GetRewardList(uid, rs.Id)
t.CheckErr(err) t.CheckErr(err)
t.JSON(map[string]interface{}{ t.JSON(map[string]interface{}{

27
controllers/common/wechat_oauth.go

@ -4,10 +4,9 @@ import (
"crypto/sha1" "crypto/sha1"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"go.uber.org/atomic"
"hudongzhuanjia/controllers" "hudongzhuanjia/controllers"
"hudongzhuanjia/libs/filter" "hudongzhuanjia/libs/filter"
"hudongzhuanjia/logger"
"hudongzhuanjia/services/pay"
"os" "os"
"time" "time"
) )
@ -57,20 +56,32 @@ func (t *WeChatOauthCtl) Checkin() {
// //
//} //}
type CDATA struct {
Text string `xml:",cdata"`
}
type CallbackParam struct { type CallbackParam struct {
XMLName xml.Name `xml:"xml"` XMLName xml.Name `xml:"xml"`
ReturnCode string `xml:"return_code"`
ReturnMsg string `xml:"return_msg"`
ReturnCode CDATA `xml:"return_code"`
ReturnMsg CDATA `xml:"return_msg"`
} }
var counter = new(atomic.Int64)
func (t *WeChatOauthCtl) CallbackOrder() { func (t *WeChatOauthCtl) CallbackOrder() {
counter.Add(1)
// 搜索支付的order表, 查找到某条记录 // 搜索支付的order表, 查找到某条记录
logger.Sugar.Infof("%s", t.Request.OriginRequest.RemoteAddr)
t.CheckErr(pay_service.NotifyOrder(t.Request.OriginRequest))
//t.CheckErr(pay_service.NotifyOrder(t.Request.OriginRequest))
param := new(CallbackParam) param := new(CallbackParam)
param.ReturnCode = "SUCCESS"
param.ReturnMsg = "OK"
param.ReturnCode = CDATA{Text: "SUCCESS"}
param.ReturnMsg = CDATA{Text: "OK"}
xmlRes, _ := xml.Marshal(param) xmlRes, _ := xml.Marshal(param)
if t.Request.OriginRequest.Method == "GET" {
t.JSON(map[string]interface{}{
"counter": counter.Load(),
"time": time.Now(),
})
}
t.XML(xmlRes) t.XML(xmlRes)
} }

27
controllers/pc/bully_screen.go

@ -3,6 +3,7 @@ package pc
import ( import (
"hudongzhuanjia/controllers" "hudongzhuanjia/controllers"
"hudongzhuanjia/models" "hudongzhuanjia/models"
bully_reward_service "hudongzhuanjia/services/bully_reward"
"hudongzhuanjia/services/pay" "hudongzhuanjia/services/pay"
"hudongzhuanjia/utils" "hudongzhuanjia/utils"
"hudongzhuanjia/utils/code" "hudongzhuanjia/utils/code"
@ -17,11 +18,6 @@ type BullyScreenCtl struct {
controllers.AuthorCtl controllers.AuthorCtl
} }
type BullyScreenBaseResult struct {
models.BullyScreenHistory `xorm:"extends"`
User *models.User `json:"user" xorm:"extends"`
}
//获取待审核列表 //获取待审核列表
func (t *BullyScreenCtl) WaitReview() { func (t *BullyScreenCtl) WaitReview() {
activityId := t.MustGetInt64("activity_id") activityId := t.MustGetInt64("activity_id")
@ -38,11 +34,8 @@ func (t *BullyScreenCtl) WaitReview() {
t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏不存在") t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏不存在")
//根据霸屏服务得id获取待审核得霸屏列表 //根据霸屏服务得id获取待审核得霸屏列表
result := make([]*BullyScreenBaseResult, 0)
err = core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", "ox_user as u", "h.user_id=u.id and u.is_delete=0").
Where("h.bully_screen_server_id=? and h.is_delete=0 and h.status=0 and h.rehearsal_id=?",
bullyScreenServer.Id, activity.RehearsalId).Desc("h.created_at").Find(&result)
t.CheckErr(bully_reward_service.CheckBullyScreenStatus(bullyScreenServer.Id))
result, err := bully_reward_service.GetBullyScreenReview(bullyScreenServer.Id, activity.RehearsalId)
t.CheckErr(err) t.CheckErr(err)
t.JSON(map[string]interface{}{ t.JSON(map[string]interface{}{
@ -132,11 +125,7 @@ func (t *BullyScreenCtl) Blacklist() {
t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏活动不存在") t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏活动不存在")
//根据霸屏服务得id获取待审核得霸屏列表 //根据霸屏服务得id获取待审核得霸屏列表
result := make([]*BullyScreenBaseResult, 0)
err = core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "u.id=h.user_id and u.is_delete=0").
Where("h.is_delete=0 and h.bully_screen_server_id=? and h.status=1 and h.rehearsal_id=?",
bullyScreenServer.Id, activity.RehearsalId).Desc("review_time").Find(&result)
result, err := bully_reward_service.GetBullyScreenBlacklist(bullyScreenServer.Id, activity.RehearsalId)
t.CheckErr(err) t.CheckErr(err)
t.DisplayByData(map[string]interface{}{ t.DisplayByData(map[string]interface{}{
@ -186,13 +175,9 @@ func (t *BullyScreenCtl) Latest() {
t.CheckErr(err) t.CheckErr(err)
t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏不存在") t.Assert(exist, code.MSG_BULLY_SCREEN_SERVER_NOT_EXIST, "霸屏不存在")
result := new(BullyScreenBaseResult)
exist, err = core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "u.id=h.user_id and u.is_delete=0").
Where("h.bully_screen_server_id=? and h.status=2 and h.rehearsal_id=? and h.is_delete=0",
bullyScreenServer.Id, activity.RehearsalId).Desc("review_time").Get(result)
result, err := bully_reward_service.GetBullyScreenLatest(bullyScreenServer.Id, activity.RehearsalId)
t.CheckErr(err) t.CheckErr(err)
if !exist {
if result == nil || result.Id == 0 {
t.RAW(result) t.RAW(result)
} }

34
controllers/pc/reward.go

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"hudongzhuanjia/controllers" "hudongzhuanjia/controllers"
"hudongzhuanjia/models" "hudongzhuanjia/models"
bully_reward_service "hudongzhuanjia/services/bully_reward"
"hudongzhuanjia/services/pay" "hudongzhuanjia/services/pay"
"hudongzhuanjia/utils" "hudongzhuanjia/utils"
"hudongzhuanjia/utils/code" "hudongzhuanjia/utils/code"
@ -16,10 +17,6 @@ import (
type RewardCtl struct { type RewardCtl struct {
controllers.AuthorCtl controllers.AuthorCtl
} }
type RewardResult struct {
models.RewardHistory `xorm:"extends"`
User *models.User `json:"user" xorm:"extends"`
}
//获取最新的打赏记录 //获取最新的打赏记录
func (t *RewardCtl) Latest() { func (t *RewardCtl) Latest() {
@ -32,13 +29,9 @@ func (t *RewardCtl) Latest() {
t.CheckErr(err) t.CheckErr(err)
t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在") t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在")
result := new(RewardResult)
exist, err = core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=2 and h.reward_server_id=? and h.rehearsal_id=?", server.Id, rehearsalId).
OrderBy("review_time desc").Get(result)
result, err := bully_reward_service.GetRewardLatest(server.Id, rehearsalId)
t.CheckErr(err) t.CheckErr(err)
if !exist {
if result == nil || result.Id == 0 {
t.RAW(result) t.RAW(result)
} }
@ -65,14 +58,10 @@ func (t *RewardCtl) WaitReview() {
t.CheckErr(err) t.CheckErr(err)
t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在") t.Assert(exist, code.MSG_REWARD_NOT_EXIST, "打赏不存在")
t.CheckErr(pay_service.BatchQueryByActivityId(activityId))
t.CheckErr(pay_service.BatchQueryRefundByActivityId(activityId))
// todo: 检查订单
t.CheckErr(bully_reward_service.CheckRewardStatus(server.Id))
result := make([]*RewardResult, 0)
err = core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=0 and h.reward_server_id=? and h.rehearsal_id=?",
server.Id, rehearsalId).OrderBy("h.created_at desc").Find(&result)
result, err := bully_reward_service.GetRewardReview(server.Id, rehearsalId)
t.CheckErr(err) t.CheckErr(err)
//根据打赏服务得id获取待审核得打赏列表 //根据打赏服务得id获取待审核得打赏列表
@ -94,11 +83,6 @@ func (t *RewardCtl) Review() {
err := core.GetXormAuto().Where("is_delete=0").In("id", ids).Find(&result) err := core.GetXormAuto().Where("is_delete=0").In("id", ids).Find(&result)
t.CheckErr(err) t.CheckErr(err)
//if rehearsalId != 0 { // 彩排不需要金额
// t.RAW("审核成功")
// return
//}
// 审核 // 审核
for _, v := range result { for _, v := range result {
if v.Status != 0 { if v.Status != 0 {
@ -189,11 +173,7 @@ func (t *RewardCtl) Blacklist() {
// 根据打赏服务id获取待审核的名单 // 根据打赏服务id获取待审核的名单
// status=true 代表审核不通过还是通过 // status=true 代表审核不通过还是通过
// 目前表示不通过,bully_screen也一样 // 目前表示不通过,bully_screen也一样
result := make([]*RewardResult, 0)
err = core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=1 and h.reward_server_id=? and h.rehearsal_id=?",
server.Id, rehearsalId).OrderBy("review_time desc").Find(&result)
result, err := bully_reward_service.GetRewardBlacklist(server.Id, rehearsalId)
t.CheckErr(err) t.CheckErr(err)
t.JSON(map[string]interface{}{ t.JSON(map[string]interface{}{

1
go.mod

@ -33,6 +33,7 @@ require (
github.com/xormplus/builder v0.0.0-20200331055651-240ff40009be // indirect github.com/xormplus/builder v0.0.0-20200331055651-240ff40009be // indirect
github.com/xormplus/core v0.0.0-20200308074340-f3bce19d5f31 // indirect github.com/xormplus/core v0.0.0-20200308074340-f3bce19d5f31 // indirect
github.com/xormplus/xorm v0.0.0-20200410045938-f6b4c1cd3b8b github.com/xormplus/xorm v0.0.0-20200410045938-f6b4c1cd3b8b
go.uber.org/atomic v1.6.0
go.uber.org/zap v1.14.1 go.uber.org/zap v1.14.1
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a // indirect golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a // indirect
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect

9
libs/im/im.go

@ -22,8 +22,9 @@ type NoticeType int
const NoticeLiveRedPackStart NoticeType = 256 // 通知直播用户红包开始了 const NoticeLiveRedPackStart NoticeType = 256 // 通知直播用户红包开始了
const NoticeLiveRedPackEnd NoticeType = 257 // 通知直播用户红包结束了 const NoticeLiveRedPackEnd NoticeType = 257 // 通知直播用户红包结束了
const NoticeShakeRedPackStart NoticeType = 258 // 通知摇红包开始了
const NoticeShakeRedPackEnd NoticeType = 259 // 通知摇红包结束了
const NoticeLiveRedPackGet NoticeType = 258 // 某人摇中红包
const NoticeShakeRedPackStart NoticeType = 259 // 通知摇红包开始了
const NoticeShakeRedPackEnd NoticeType = 260 // 通知摇红包结束了
type CommonResult struct { type CommonResult struct {
ActionStatus string `json:"ActionStatus"` ActionStatus string `json:"ActionStatus"`
@ -79,7 +80,7 @@ type SendGroupSystemNotificationParam struct {
ToMembersAccount []string `json:"ToMembers_Account,omitempty"` ToMembersAccount []string `json:"ToMembers_Account,omitempty"`
} }
func SendGroupSystemNotification(groupId string, noticeType NoticeType, notice string, members ...string) error {
func SendGroupSystemNotification(groupId string, noticeType NoticeType, data map[string]interface{}, members ...string) error {
sig, err := GenSig("admin") sig, err := GenSig("admin")
if err != nil { if err != nil {
return err return err
@ -90,7 +91,7 @@ func SendGroupSystemNotification(groupId string, noticeType NoticeType, notice s
var m = make(map[string]interface{}) var m = make(map[string]interface{})
m["type"] = noticeType m["type"] = noticeType
m["notice"] = notice
m["data"] = data
content, err := json.Marshal(&m) content, err := json.Marshal(&m)
if err != nil { if err != nil {
return err return err

2
log/hdzj.log

@ -15,3 +15,5 @@
2020-04-07 14:31:17.846 ERROR logger/logger.go:92 check err {"error": "Error 1146: Table 'hudongzhuanjia.ox_live_viewer' doesn't exist"} 2020-04-07 14:31:17.846 ERROR logger/logger.go:92 check err {"error": "Error 1146: Table 'hudongzhuanjia.ox_live_viewer' doesn't exist"}
2020-04-07 14:33:15.037 ERROR logger/logger.go:92 check err {"error": "Error 1292: Incorrect datetime value: '' for column 'created_at' at row 1"} 2020-04-07 14:33:15.037 ERROR logger/logger.go:92 check err {"error": "Error 1292: Incorrect datetime value: '' for column 'created_at' at row 1"}
2020-04-07 14:33:46.303 ERROR logger/logger.go:92 check err {"error": "Error 1292: Incorrect datetime value: '' for column 'created_at' at row 1"} 2020-04-07 14:33:46.303 ERROR logger/logger.go:92 check err {"error": "Error 1292: Incorrect datetime value: '' for column 'created_at' at row 1"}
2020-04-16 14:25:59.479 INFO common/wechat_oauth.go:68 127.0.0.1:5000
2020-04-16 14:25:59.490 ERROR logger/logger.go:92 check err {"error": "xml.NewDecoder.Decode:EOF"}

26
models/bully_screen_history.go

@ -20,7 +20,7 @@ type BullyScreenHistory struct {
Style int `json:"style" xorm:"not null comment('服务样式') INT(11)"` Style int `json:"style" xorm:"not null comment('服务样式') INT(11)"`
Second int `json:"second" xorm:"not null comment('霸屏时间(秒)') INT(11)"` Second int `json:"second" xorm:"not null comment('霸屏时间(秒)') INT(11)"`
Content string `json:"content" xorm:"not null comment('内容') TEXT"` Content string `json:"content" xorm:"not null comment('内容') TEXT"`
Status int `json:"status" xorm:"not null default(0) comment('[-1未支付,0未审核,1未通过,2已通过,3已推送,4已退款,5被取消]') INT(11)"`
Status int `json:"status" xorm:"not null default(0) comment('[-1未支付,0未审核,1未通过,2已通过,3已推送,4已作废]') INT(11)"`
Amount float64 `json:"amount" xorm:"not null default 0.00 comment('霸屏金额') DECIMAL(10)"` Amount float64 `json:"amount" xorm:"not null default 0.00 comment('霸屏金额') DECIMAL(10)"`
ReviewTime int64 `json:"review_time" xorm:"not null comment('审核的时间') INT(11)"` ReviewTime int64 `json:"review_time" xorm:"not null comment('审核的时间') INT(11)"`
Version int64 `json:"version" xorm:"not null version comment('乐观锁') INT(11)"` Version int64 `json:"version" xorm:"not null version comment('乐观锁') INT(11)"`
@ -38,22 +38,20 @@ func (t *BullyScreenHistory) UpdateStatus(id int64, status int) (int64, error) {
return core.GetXormAuto().ID(id).Cols("status").Update(t) return core.GetXormAuto().ID(id).Cols("status").Update(t)
} }
//
//func (t *BullyScreenHistory) UpdateStatusByUserOrderId(userOrderId interface{}, status int) (int64, error) {
// t.Status = status
// return core.GetXormAuto().Where("is_delete=0 and user_order_id=?", userOrderId).
// Cols("status").Update(t)
//}
func GetBullyScreenHistoriesByStatus(status int) ([]*BullyScreenHistory, error) {
histories := make([]*BullyScreenHistory, 0)
err := core.GetXormAuto().Where("is_delete and status=?", status).Find(&histories)
return histories, err
}
// 更改未支付状态 // 更改未支付状态
func (t *BullyScreenHistory) UpdateStatusByOutTradeNo(outTradeNo string, status int) (int64, error) { func (t *BullyScreenHistory) UpdateStatusByOutTradeNo(outTradeNo string, status int) (int64, error) {
t.Status = status t.Status = status
return core.GetXormAuto().Where("is_delete=0 and status=-1 and out_trade_no=?", outTradeNo). return core.GetXormAuto().Where("is_delete=0 and status=-1 and out_trade_no=?", outTradeNo).
Cols("status").Update(t) Cols("status").Update(t)
} }
func (t *BullyScreenHistory) UpdateStatusByIds(ids []int64, status int) error {
if len(ids) > 0 {
t.Status = status
_, err := core.GetXormAuto().In("id", ids).Cols("status").
Update(&BullyScreenHistory{Status: status})
return err
}
return nil
}

1
models/init_models.go

@ -88,6 +88,7 @@ func init() {
new(LiveConfig), new(LiveConfig),
new(LiveRedPackInfo), new(LiveRedPackInfo),
new(LiveRedPack), new(LiveRedPack),
new(UserTransfer),
) )
fmt.Printf("error=======>%v\n\n", err) fmt.Printf("error=======>%v\n\n", err)
} }

2
models/live_red_pack.go

@ -19,7 +19,7 @@ type LiveRedPack struct {
OpenId string `json:"open_id" xorm:"not null default '' comment('用户openid') VARCHAR(128)"` OpenId string `json:"open_id" xorm:"not null default '' comment('用户openid') VARCHAR(128)"`
Amount int `json:"amount" xorm:"not null default 0 comment('红包金额, 分') INT(18)"` Amount int `json:"amount" xorm:"not null default 0 comment('红包金额, 分') INT(18)"`
TransferType int `json:"transfer_type" xorm:"not null default 0 comment('转账方式[0微信红包1微信零钱]') TINYINT(1)"` TransferType int `json:"transfer_type" xorm:"not null default 0 comment('转账方式[0微信红包1微信零钱]') TINYINT(1)"`
TransferNo string `json:"transfer_no" xorm:"not null default '' comment('转账账号') VARCHAR(128) "`
PartnerTradeNo string `json:"partner_trade_no" xorm:"not null default '' comment('转账单号') VARCHAR(128) "`
Status int `json:"status" xorm:"not null default 0 comment('0 未被领取 1 已被领取 2 已发送 3 出现错误') TINYINT(1)"` Status int `json:"status" xorm:"not null default 0 comment('0 未被领取 1 已被领取 2 已发送 3 出现错误') TINYINT(1)"`
Version int `json:"version" xorm:"not null version comment('乐观锁') INT(11)"` Version int `json:"version" xorm:"not null version comment('乐观锁') INT(11)"`
} }

3
models/live_red_pack_info.go

@ -15,11 +15,12 @@ type LiveRedPackInfo struct {
UserId int64 `json:"user_id" xorm:"not null default 0 comment('用户id') INT(11)"` UserId int64 `json:"user_id" xorm:"not null default 0 comment('用户id') INT(11)"`
ActivityId int64 `json:"activity_id" xorm:"not null default 0 comment('互动id') INT(11)"` ActivityId int64 `json:"activity_id" xorm:"not null default 0 comment('互动id') INT(11)"`
GroupId string `json:"group_id" xorm:"not null default '' comment('聊天室地址') VARCHAR(128)"`
Prompt string `json:"prompt" xorm:"not null default 0 comment('祝福语') VARCHAR(255)"` Prompt string `json:"prompt" xorm:"not null default 0 comment('祝福语') VARCHAR(255)"`
Amount int64 `json:"amount" xorm:"not null default 0 comment('红包金额, 分') INT(18)"` Amount int64 `json:"amount" xorm:"not null default 0 comment('红包金额, 分') INT(18)"`
OutTradeNo string `json:"out_trade_no" xorm:"not null default '' comment('订单号') VARCHAR(128)"` OutTradeNo string `json:"out_trade_no" xorm:"not null default '' comment('订单号') VARCHAR(128)"`
Error string `json:"error" xorm:"not null default '' comment('出现错误') VARCHAR(255)"` Error string `json:"error" xorm:"not null default '' comment('出现错误') VARCHAR(255)"`
Status int `json:"status" xorm:"not null default 0 comment('-1尚未支付0支付成功1已推送')"`
Status int `json:"status" xorm:"not null default 0 comment('-1尚未支付0支付成功1已推送2已作废')"`
} }
func (t *LiveRedPackInfo) TableName() string { func (t *LiveRedPackInfo) TableName() string {

16
models/reward_history.go

@ -19,7 +19,7 @@ type RewardHistory struct {
Content string `json:"content" xorm:"not null comment('内容') text"` Content string `json:"content" xorm:"not null comment('内容') text"`
Amount float64 `json:"amount" xorm:"not null default(0.0) comment('金额') DECIMAL"` Amount float64 `json:"amount" xorm:"not null default(0.0) comment('金额') DECIMAL"`
RewardAmount string `json:"reward_amount" xorm:"-" description:"同上, 字符串"` RewardAmount string `json:"reward_amount" xorm:"-" description:"同上, 字符串"`
Status int `json:"status" xorm:"not null default(0) comment('-1未支付,0未审核,1未通过,2已通过,3已推送,4已退款,5被取消') INT(11)"`
Status int `json:"status" xorm:"not null default(0) comment('-1未支付,0未审核,1未通过,2已通过,3已推送,4已作废') INT(11)"`
ReviewTime int64 `json:"review_time" xorm:"not null default(0) comment('审核时间') INT(11)"` ReviewTime int64 `json:"review_time" xorm:"not null default(0) comment('审核时间') INT(11)"`
Version int64 `json:"version" xorm:"not null version comment('乐观锁') INT(11)"` Version int64 `json:"version" xorm:"not null version comment('乐观锁') INT(11)"`
IsDelete bool `json:"is_delete" xorm:"not null default(0)"` IsDelete bool `json:"is_delete" xorm:"not null default(0)"`
@ -40,12 +40,16 @@ func (t *RewardHistory) UpdateStatus(id int64, status int) (int64, error) {
return core.GetXormAuto().Where("id=?", id).Cols("status").Update(t) return core.GetXormAuto().Where("id=?", id).Cols("status").Update(t)
} }
//func (t *RewardHistory) UpdateStatusByUserOrderId(userOrderId interface{}, status int) (int64, error) {
// t.Status = status
// return core.GetXormAuto().Where("is_delete=0 and user_order_id=?", userOrderId).Cols("status").Update(t)
//}
func (t *RewardHistory) UpdateStatusByOutTradeNo(outTradeNo string, status int) (int64, error) { func (t *RewardHistory) UpdateStatusByOutTradeNo(outTradeNo string, status int) (int64, error) {
t.Status = status t.Status = status
return core.GetXormAuto().Where("is_delete=0 and status=-1 and out_trade_no=?", outTradeNo).Update(status) return core.GetXormAuto().Where("is_delete=0 and status=-1 and out_trade_no=?", outTradeNo).Update(status)
} }
func (t *RewardHistory) UpdateStatusByIds(ids []int64, status int) error {
if len(ids) > 0 {
_, err := core.GetXormAuto().In("id", ids).Cols("status").
Update(&RewardHistory{Status: status})
return err
}
return nil
}

24
models/user_order.go

@ -16,7 +16,7 @@ type UserOrder struct {
// 订单信息 // 订单信息
DeviceInfo string `json:"device_info" xorm:"not null default('') comment('设备号') VARCHAR(32)"` DeviceInfo string `json:"device_info" xorm:"not null default('') comment('设备号') VARCHAR(32)"`
GoodType int64 `json:"good_type" xorm:"not null default(0) comment('1霸屏2打赏3直播红包')"` GoodType int64 `json:"good_type" xorm:"not null default(0) comment('1霸屏2打赏3直播红包')"`
Desc string `json:"desc" xorm:"not null default('') comment('') VARCHAR(128)"`
Body string `json:"body" xorm:"not null default('') comment('') VARCHAR(128)"`
OutTradeNo string `json:"out_trade_no" xorm:"not null default('') comment('商户订单号') VARCHAR(32)"` OutTradeNo string `json:"out_trade_no" xorm:"not null default('') comment('商户订单号') VARCHAR(32)"`
FeeType string `json:"fee_type" xorm:"not null default('CNY') comment('货币种类') VARCHAR(16)"` FeeType string `json:"fee_type" xorm:"not null default('CNY') comment('货币种类') VARCHAR(16)"`
TotalFee int64 `json:"total_fee" xorm:"not null default(0) comment('订单总金额,单位是分') INT(88)"` TotalFee int64 `json:"total_fee" xorm:"not null default(0) comment('订单总金额,单位是分') INT(88)"`
@ -30,7 +30,7 @@ type UserOrder struct {
TimeEnd string `json:"time_end" xorm:"not null default('') comment('交易结算时间') VARCHAR(14)"` TimeEnd string `json:"time_end" xorm:"not null default('') comment('交易结算时间') VARCHAR(14)"`
PrepayId string `json:"prepay_id" xorm:"not null default('') comment('预支付交易会话标识') VARCHAR(64)"` PrepayId string `json:"prepay_id" xorm:"not null default('') comment('预支付交易会话标识') VARCHAR(64)"`
Status int `json:"status" xorm:"not null default(0) comment('0尚未支付/支付中1支付成功2已撤销3转入退款4退款成功5支付失败6订单关闭') TINYINT(1)"` Status int `json:"status" xorm:"not null default(0) comment('0尚未支付/支付中1支付成功2已撤销3转入退款4退款成功5支付失败6订单关闭') TINYINT(1)"`
ErrMsg string `json:"err_msg" xorm:"not null default 0 comment('出现错误') VARCHAR(255)"`
ErrMsg string `json:"err_msg" xorm:"not null default '' comment('出现错误') VARCHAR(255)"`
// 退款 // 退款
SuccessTime time.Time `json:"success_time" xorm:"not null default '' comment('退款成功时间') VARCHAR(20)"` SuccessTime time.Time `json:"success_time" xorm:"not null default '' comment('退款成功时间') VARCHAR(20)"`
@ -42,6 +42,10 @@ func (t *UserOrder) TableName() string {
return UserOrderTableName return UserOrderTableName
} }
func (t *UserOrder) AliasName(alias string) string {
return AliasTableName(t, alias)
}
func (t *UserOrder) AddUserOrder() (int64, error) { func (t *UserOrder) AddUserOrder() (int64, error) {
return core.GetXormAuto().InsertOne(t) return core.GetXormAuto().InsertOne(t)
} }
@ -69,20 +73,8 @@ func (t *UserOrder) UpdateRefundByOutTradeNo(outTradeNo interface{}) (int64, err
return core.GetXormAuto().Where("out_trade_no=?", outTradeNo).Cols("success_time", "refund_recv_account", "refund_account").Update(t) return core.GetXormAuto().Where("out_trade_no=?", outTradeNo).Cols("success_time", "refund_recv_account", "refund_account").Update(t)
} }
func GetUserOrdersByStatusAndUserId(userId interface{}, status int) ([]*UserOrder, error) {
orders := make([]*UserOrder, 0)
err := core.GetXormAuto().Where("is_delete = 0 and status = ? and user_id = ?", status, userId).Find(&orders)
return orders, err
}
func GetUserOrdersByStatusAndActivityId(activityId interface{}, status int) ([]*UserOrder, error) {
orders := make([]*UserOrder, 0)
err := core.GetXormAuto().Where("is_delete = 0 and status = ? and activity_id = ?", status, activityId).Find(&orders)
return orders, err
}
func GetValidUserOrders() ([]*UserOrder, error) {
func GetUserOrdersByStatus(status ...int) ([]*UserOrder, error) {
orders := make([]*UserOrder, 0) orders := make([]*UserOrder, 0)
err := core.GetXormAuto().Where("is_delete=0 and (status=? or status=?)", 0, 3).Find(&orders)
err := core.GetXormAuto().Where("is_delete=0").In("status", status).Find(&orders)
return orders, err return orders, err
} }

53
models/user_transfer.go

@ -0,0 +1,53 @@
package models
import (
"github.com/ouxuanserver/osmanthuswine/src/core"
"time"
)
const UserTransferTN = TableNamePrefix + "user_transfer"
type UserTransfer struct {
Id int64 `json:"id" xorm:"not null pk autoincr INT(11)"`
CreatedAt time.Time `json:"created_at" xorm:"created comment('创建时间') TIMESTAMP"`
UpdatedAt time.Time `json:"updated_at" xorm:"updated comment('更新时间') TIMESTAMP"`
IsDelete int `json:"is_delete" xorm:"not null default 0 comment('是否删除') TINYINT(1)"`
DeviceInfo string `json:"device_info" xorm:"not null default '' comment('设备信息') VARCHAR(32)"`
NonceStr string `json:"nonce_str" xorm:"not null default '' comment('随机字符串') VARCHAR(32)"`
PartnerTradeNo string `json:"partner_trade_no" xorm:"not null default '' comment('商户订单号') VARCHAR(32)"`
PaymentNo string `json:"payment_no" xorm:"not null default '' comment('微信付款单号') VARCHAR(64)"`
PaymentTime string `json:"payment_time" xorm:"not null default '' comment('企业付款成功时间') VARCHAR(32)"`
Status int `json:"status" xorm:"not null default 0 comment('0未处理1处理中2转账成功3转账失败4查询尝试失败') TINYINT(1)"`
Reason string `json:"reason" xorm:"not null default '' comment('转账失败原因') VARCHAR(255)"`
OpenId string `json:"open_id" xorm:"not null default '' comment('用户open_id') VARCHAR(64)"`
PaymentAmount int `json:"payment_amount" xorm:"not null default 0 comment('转账金额,单位分') INT(18)"`
TransferTime string `json:"transfer_time" xorm:"not null default '' comment('转账时间') VARCHAR(32)"`
Desc string `json:"desc" xorm:"not null default '' comment('备注') VARCHAR(128)"`
ErrMsg string `json:"err_msg" xorm:"not null default '' comment('错误信息') VARCHAR(255)"`
}
func (t *UserTransfer) TableName() string {
return UserTransferTN
}
func GetUserTransferByStatus(status ...int) ([]*UserTransfer, error) {
transfers := make([]*UserTransfer, 0)
err := core.GetXormAuto().Where("is_delete=0").In("status", status).Find(&transfers)
return transfers, err
}
func (t *UserTransfer) Add() (int64, error) {
return core.GetXormAuto().InsertOne(t)
}
func (t *UserTransfer) GetByPartnerTradeNo(partnerTradeNo string) (bool, error) {
return core.GetXormAuto().Where("is_delete=0 and partner_trade_no=?", partnerTradeNo).Get(t)
}
func (t *UserTransfer) UpdateByPartnerTradeNo(partnerTradeNo string) (int64, error) {
return core.GetXormAuto().Where("is_delete=0 and partner_trade_no=?", partnerTradeNo).Update(t)
}
func (t *UserTransfer) UpdateErrMsg(partnerTradeNo, msg string) (int64, error) {
return core.GetXormAuto().Where("is_delete=0 and partner_trade_no=?", partnerTradeNo).Update(&UserTransfer{ErrMsg: msg})
}

140
services/bully_reward/dao.go

@ -34,3 +34,143 @@ func GetRewardList(userId, rewardId int64) ([]*RewardListResult, error) {
Desc("created_at").Find(&list) Desc("created_at").Find(&list)
return list, err return list, err
} }
type RewardResult struct {
models.RewardHistory `xorm:"extends"`
User *models.User `json:"user" xorm:"extends"`
}
func GetRewardLatest(serverId, rehearsalId int64) (*RewardResult, error) {
result := new(RewardResult)
_, err := core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"),
"h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=2 and h.reward_server_id=? and h.rehearsal_id=?",
serverId, rehearsalId).Desc("h.review_time").Get(result)
return result, err
}
func GetRewardReview(serverId, rehearsalId int64) ([]*RewardResult, error) {
result := make([]*RewardResult, 0)
err := core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"),
"h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=0 and h.reward_server_id=? and h.rehearsal_id=?",
serverId, rehearsalId).Desc("h.created_at").Find(&result)
return result, err
}
func GetRewardBlacklist(serverId, rehearsalId int64) ([]*RewardResult, error) {
result := make([]*RewardResult, 0)
err := core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"),
"h.user_id=u.id and u.is_delete=0").
Where("h.is_delete=0 and h.status=1 and h.reward_server_id=? and h.rehearsal_id=?",
serverId, rehearsalId).Desc("h.review_time").Find(&result)
return result, err
}
type RewardStatus struct {
History *models.RewardHistory `json:"history" xorm:"extends"`
Order *models.UserOrder `json:"order" xorm:"extends"`
}
func CheckRewardStatus(serverId int64) error {
result := make([]*RewardStatus, 0)
err := core.GetXormAuto().Table(new(models.RewardHistory)).Alias("h").
Join("LEFT", new(models.UserOrder).AliasName("u"),
"h.out_trade_no=u.out_trade_no and u.is_delete=0").
Where("h.is_delete=0 and h.status=-1 and h.reward_server_id=?",
serverId).Find(&result)
if err != nil {
return err
}
success := make([]int64, 0)
destroy := make([]int64, 0)
for _, v := range result {
if v.Order.Status == 1 {
success = append(success, v.History.Id)
} else if v.Order.Status != 0 {
destroy = append(destroy, v.History.Id)
}
}
err = new(models.RewardHistory).UpdateStatusByIds(success, 0)
if err != nil {
return err
}
err = new(models.RewardHistory).UpdateStatusByIds(success, 4)
if err != nil {
return err
}
return nil
}
type BullyScreenResult struct {
models.BullyScreenHistory `xorm:"extends"`
User *models.User `json:"user" xorm:"extends"`
}
func GetBullyScreenReview(bullyScreenServerId, rehearsalId int64) ([]*BullyScreenResult, error) {
result := make([]*BullyScreenResult, 0)
err := core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"),
"h.user_id=u.id and u.is_delete=0").
Where("h.bully_screen_server_id=? and h.is_delete=0 and h.status=0 and h.rehearsal_id=?",
bullyScreenServerId, rehearsalId).Desc("h.created_at").Find(&result)
return result, err
}
func GetBullyScreenBlacklist(bullyScreenServerId, rehearsalId int64) ([]*BullyScreenResult, error) {
result := make([]*BullyScreenResult, 0)
err := core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "u.id=h.user_id and u.is_delete=0").
Where("h.is_delete=0 and h.bully_screen_server_id=? and h.status=1 and h.rehearsal_id=?",
bullyScreenServerId, rehearsalId).Desc("review_time").Find(&result)
return result, err
}
func GetBullyScreenLatest(bullyScreenServerId, rehearsalId int64) (*BullyScreenResult, error) {
result := new(BullyScreenResult)
_, err := core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.User).Alias("u"), "u.id=h.user_id and u.is_delete=0").
Where("h.bully_screen_server_id=? and h.status=2 and h.rehearsal_id=? and h.is_delete=0",
bullyScreenServerId, rehearsalId).Desc("review_time").Get(result)
return result, err
}
type BullyScreenStatus struct {
History *models.BullyScreenHistory `json:"history" xorm:"extends"`
Order *models.UserOrder `json:"order" xorm:"extends"`
}
func CheckBullyScreenStatus(bullyScreenServerId int64) error {
result := make([]*BullyScreenStatus, 0)
err := core.GetXormAuto().Table(new(models.BullyScreenHistory)).Alias("h").
Join("LEFT", new(models.UserOrder).AliasName("u"),
"u.out_trade_no=h.out_trade_no and u.is_delete=0").
Where("h.bully_screen_server_id=? and h.status=-1 and h.is_delete=0",
bullyScreenServerId).Find(&result)
if err != nil {
return err
}
success := make([]int64, 0)
destroy := make([]int64, 0)
for _, v := range result {
if v.Order.Status == 1 {
success = append(success, v.History.Id)
} else if v.Order.Status != 0 {
destroy = append(destroy, v.History.Id)
}
}
err = new(models.BullyScreenHistory).UpdateStatusByIds(success, 0)
if err != nil {
return err
}
err = new(models.BullyScreenHistory).UpdateStatusByIds(success, 4)
if err != nil {
return err
}
return nil
}

19
services/im/im.go

@ -0,0 +1,19 @@
package im_service
import (
"errors"
"hudongzhuanjia/libs/im"
"hudongzhuanjia/models"
)
func SendNoticeByActivityId(activityId int64, data map[string]interface{}, members ...string) error {
live := new(models.LiveConfig)
exist, err := live.GetByActivityId(activityId)
if err != nil {
return err
}
if !exist {
return errors.New("直播信息不存在")
}
return im.SendGroupSystemNotification(live.ImGroupId, im.NoticeLiveRedPackStart, data, members...)
}

4
services/pay/const.go

@ -64,11 +64,13 @@ const (
CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制 CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制
CODE_TRADE_SUCCESS = "SUCCESS" // 交易成功 CODE_TRADE_SUCCESS = "SUCCESS" // 交易成功
CODE_TRADE_REFUND = "REFUND" // 转入退款 CODE_TRADE_REFUND = "REFUND" // 转入退款
CODE_TRADE_NOTPAY = "NOTPAY" // 尚未退款
CODE_TRADE_NOTPAY = "NOTPAY" // 尚未支付
CODE_TRADE_CLOSED = "CLOSED" // 已关闭 CODE_TRADE_CLOSED = "CLOSED" // 已关闭
CODE_TRADE_REVOKED = "REVOKED" // 已撤销 CODE_TRADE_REVOKED = "REVOKED" // 已撤销
CODE_TRADE_USERPAYING = "USERPAYING" // 用户支付中 CODE_TRADE_USERPAYING = "USERPAYING" // 用户支付中
CODE_TRADE_PAYERROR = "PAYERROR" // 支付失败 CODE_TRADE_PAYERROR = "PAYERROR" // 支付失败
CODE_TRANSFER_PROCESSING = "PROCESSING" // 转账处理中
CODE_TRANSFER_NOT_FOUND = "NOT_FOUND" // 账单消息
) )
type CommonReturn struct { type CommonReturn struct {

224
services/pay/order.go

@ -1,8 +1,6 @@
package pay_service package pay_service
import ( import (
"encoding/xml"
"fmt"
core2 "github.com/chanxuehong/wechat/mch/core" core2 "github.com/chanxuehong/wechat/mch/core"
"github.com/chanxuehong/wechat/mch/pay" "github.com/chanxuehong/wechat/mch/pay"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -10,33 +8,53 @@ import (
"hudongzhuanjia/logger" "hudongzhuanjia/logger"
"hudongzhuanjia/models" "hudongzhuanjia/models"
"hudongzhuanjia/utils" "hudongzhuanjia/utils"
"net/http"
"math"
"strconv" "strconv"
"time" "time"
) )
func init() { func init() {
go loop()
go loopUnifiedOrder()
} }
var orderChanSize = 10000
var orderChanDelay = 1
var orderChan chan string
var orderDelayQueue = make(chan *orderDelayQueueParam, math.MaxInt8)
type orderDelayQueueParam struct {
First bool `json:"first"`
Expires int64 `json:"expires"`
Delay int `json:"delay"`
OutTradeNo string `json:"out_trade_no"`
Body string `json:"body"`
Amount int `json:"amount"` // 金额
Status int `json:"status"` // 0 订单 3 退款
OpenId string `json:"open_id"` // 被操作人
}
func PutOrderDelayQueue(body, outTradeNo, openId string, amount, status int, expires int64, delay int) {
if expires == 0 {
expires = time.Now().Add(2 * time.Hour).Unix() // 2 个小时
}
func PutOrderChan(value string) {
time.Sleep(time.Duration(orderChanDelay) * time.Second)
orderChan <- value
orderDelayQueue <- &orderDelayQueueParam{
First: true,
Expires: expires,
Delay: delay,
OutTradeNo: outTradeNo,
Body: body,
Amount: amount,
Status: status,
OpenId: openId,
}
} }
func loop() {
orders, err := models.GetValidUserOrders()
func loopUnifiedOrder() {
orders, err := models.GetUserOrdersByStatus(0, 3)
if err != nil { if err != nil {
panic(err) panic(err)
} }
orderChan = make(chan string, orderChanSize+len(orders))
for _, order := range orders { for _, order := range orders {
orderChan <- order.OutTradeNo
PutOrderDelayQueue(order.Body, order.OutTradeNo, order.OpenId, int(order.TotalFee), order.Status, 0, 0)
} }
defer func() { defer func() {
@ -45,37 +63,57 @@ func loop() {
} }
// 重启 // 重启
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)
loop()
loopUnifiedOrder()
}() }()
for { for {
select { select {
case outTradeNo, ok := <-orderChan:
case param, ok := <-orderDelayQueue:
if !ok { if !ok {
panic("通道异常关闭") panic("通道异常关闭")
} }
userOrder := new(models.UserOrder)
if userOrder.Status == 0 {
res, err := OrderQuery(outTradeNo)
//userOrder := new(models.UserOrder)
//exist, err := userOrder.GetByOutTradeNo(outTradeNo)
//if err != nil || !exist {
// logger.Error("通过订单查询UserOrder", zap.String("错误原因", err.Error()),
// zap.Bool("是否存在", exist), zap.String("交易订单号", outTradeNo))
// continue
//}
if param.Expires <= time.Now().Unix() {
Close(param.OutTradeNo) // 超时关闭订单
continue // 超时
}
// 首次进入不延迟
if !param.First {
time.Sleep(time.Duration(param.Delay) * time.Second)
}
param.First = false
if param.Status == 0 {
res, err := OrderQuery(param.OutTradeNo)
// 出现错误 // 出现错误
if err != nil { if err != nil {
logger.Error("查询订单出现错误", zap.String("错误原因", err.Error()), logger.Error("查询订单出现错误", zap.String("错误原因", err.Error()),
zap.String("交易订单号", outTradeNo))
PutOrderChan(outTradeNo)
zap.String("交易订单号", param.OutTradeNo))
orderDelayQueue <- param // 重新进入队列
continue continue
} }
if res.TradeState == CODE_TRADE_SUCCESS {
if res.TradeState == CODE_TRADE_REFUND {
param.Status = 3
orderDelayQueue <- param
continue continue
} else if res.TradeState == CODE_TRADE_REFUND {
PutOrderChan(outTradeNo)
} else if res.TradeState == CODE_TRADE_NOTPAY || res.TradeState == CODE_TRADE_USERPAYING {
orderDelayQueue <- param
continue continue
} }
} else if userOrder.Status == 3 {
_, err = QueryRefund(outTradeNo)
} else if param.Status == 3 {
_, err = QueryRefund(param.OutTradeNo)
if err != nil { if err != nil {
logger.Error("退款订单查询错误", zap.String("错误原因", err.Error()), logger.Error("退款订单查询错误", zap.String("错误原因", err.Error()),
zap.String("交易订单号", outTradeNo))
zap.String("交易订单号", param.OutTradeNo))
continue
} }
} else { } else {
continue continue
@ -84,27 +122,23 @@ func loop() {
} }
} }
func init() {
go loop()
}
const CallbackOrderUrl = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackOrder" const CallbackOrderUrl = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackOrder"
func Order(content, ip, openid string, fee, goodType, userId, activityId int64) (map[string]interface{}, error) {
func UnifiedOrder(body, ip, openid string, fee, goodType, userId, activityId int64) (map[string]interface{}, error) {
client, err := Client() client, err := Client()
if err != nil { if err != nil {
return nil, err return nil, err
} }
now := time.Now() now := time.Now()
timeStart := now.Format("20060101150405")
timeExpire := now.Add(2 * time.Hour).Format("20060101150405")
timeStart := core2.FormatTime(now)
timeExpire := core2.FormatTime(now.Add(2 * time.Hour))
outTradeNo := utils.RandomStr(32) outTradeNo := utils.RandomStr(32)
nonceStr := utils.RandomStr(32) nonceStr := utils.RandomStr(32)
resp, err := pay.UnifiedOrder2(client, &pay.UnifiedOrderRequest{ resp, err := pay.UnifiedOrder2(client, &pay.UnifiedOrderRequest{
Body: content,
Body: body,
OutTradeNo: outTradeNo, OutTradeNo: outTradeNo,
TotalFee: int64(fee),
TotalFee: fee,
SpbillCreateIP: ip, SpbillCreateIP: ip,
NotifyURL: CallbackOrderUrl, NotifyURL: CallbackOrderUrl,
TradeType: "JSAPI", TradeType: "JSAPI",
@ -121,7 +155,7 @@ func Order(content, ip, openid string, fee, goodType, userId, activityId int64)
// 记录这次订单 // 记录这次订单
userOrder := new(models.UserOrder) userOrder := new(models.UserOrder)
userOrder.DeviceInfo = "WEB" userOrder.DeviceInfo = "WEB"
userOrder.Desc = content
userOrder.Body = body
userOrder.UserId = userId userOrder.UserId = userId
userOrder.ActivityId = activityId userOrder.ActivityId = activityId
userOrder.FeeType = "CNY" userOrder.FeeType = "CNY"
@ -146,7 +180,7 @@ func Order(content, ip, openid string, fee, goodType, userId, activityId int64)
pac := "prepay_id=" + resp.PrepayId pac := "prepay_id=" + resp.PrepayId
paySign := core2.JsapiSign(client.AppId(), nonceStr, pac, core2.SignType_MD5, timestamp, ApiKey) paySign := core2.JsapiSign(client.AppId(), nonceStr, pac, core2.SignType_MD5, timestamp, ApiKey)
PutOrderChan(outTradeNo)
go PutOrderDelayQueue(userOrder.Body, userOrder.OutTradeNo, userOrder.OpenId, int(userOrder.TotalFee), userOrder.Status, 5, 0)
return map[string]interface{}{ return map[string]interface{}{
"appid": Appid, "appid": Appid,
"timestamp": timestamp, "timestamp": timestamp,
@ -195,48 +229,47 @@ type NotifyRequest struct {
TimeEnd string `xml:"time_end,omitempty" json:"time_end,omitempty"` TimeEnd string `xml:"time_end,omitempty" json:"time_end,omitempty"`
} }
func NotifyOrder(req *http.Request) error {
res := new(NotifyRequest)
if err := xml.NewDecoder(req.Body).Decode(res); err != nil {
return fmt.Errorf("xml.NewDecoder.Decode:%w", err)
}
if res.ReturnCode != CODE_SUCCESS {
return fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
return fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
userOrder := new(models.UserOrder)
exist, err := userOrder.GetByOutTradeNo(res.OutTradeNo)
if err != nil {
return err
}
if !exist {
return fmt.Errorf("user order not exist")
}
userOrder.TimeEnd = res.TimeEnd
userOrder.TransactionId = res.TransactionId
userOrder.Status = 1
if _, err = userOrder.UpdateStatusById(userOrder.Id); err != nil {
return err
}
//// 设置一下
//if userOrder.GoodType == 1 { // 霸屏
// _, err = new(models.BullyScreenHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
// if err != nil {
// return err
// }
//} else if userOrder.GoodType == 2 {
// _, err = new(models.RewardHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
// if err != nil {
// return err
// }
//}
return nil
}
//func NotifyOrder(req *http.Request) error {
// res := new(NotifyRequest)
// if err := xml.NewDecoder(req.Body).Decode(res); err != nil {
// return fmt.Errorf("xml.NewDecoder.Decode:%w", err)
// }
//if res.ReturnCode != CODE_SUCCESS {
// return fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
//}
//
//if res.ResultCode != CODE_FAIL && res.ErrCode == CODE_SYSTEMERROR {
// return fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
//}
//
//if res.ResultCode == CODE_SUCCESS {
// userOrder := new(models.UserOrder)
// userOrder.TimeEnd = res.TimeEnd
// userOrder.TransactionId = res.TransactionId
// if res.TradeType == CODE_TRADE_SUCCESS {
// userOrder.Status = 1
// } else if _, err := userOrder.UpdateStatusByOutTradeNo(res.OutTradeNo, userOrder.TradeType); err != nil {
// return err
// }
//
//} else {
//}
//// 设置一下
//if userOrder.GoodType == 1 { // 霸屏
// _, err = new(models.BullyScreenHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
// if err != nil {
// return err
// }
//} else if userOrder.GoodType == 2 {
// _, err = new(models.RewardHistory).UpdateStatusByUserOrderId(userOrder.Id, 0)
// if err != nil {
// return err
// }
//}
// return nil
//}
func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) { func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) {
client, err := Client() client, err := Client()
@ -245,11 +278,20 @@ func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) {
} }
// 请求订单查询,成功后得到结果 // 请求订单查询,成功后得到结果
userOrder := new(models.UserOrder) userOrder := new(models.UserOrder)
exist, err := userOrder.GetByOutTradeNo(outTradeNo)
if err != nil {
return nil, err
}
if !exist {
return nil, errors.New("订单不存在")
}
res, err := pay.OrderQuery2(client, &pay.OrderQueryRequest{ res, err := pay.OrderQuery2(client, &pay.OrderQueryRequest{
OutTradeNo: outTradeNo, OutTradeNo: outTradeNo,
NonceStr: utils.RandomStr(32), NonceStr: utils.RandomStr(32),
SignType: core2.SignType_MD5, SignType: core2.SignType_MD5,
}) })
if err != nil { if err != nil {
userOrder.ErrMsg = err.Error() userOrder.ErrMsg = err.Error()
userOrder.UpdateErrByOutTradeNo(outTradeNo) userOrder.UpdateErrByOutTradeNo(outTradeNo)
@ -259,7 +301,6 @@ func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) {
userOrder.TransactionId = res.TransactionId userOrder.TransactionId = res.TransactionId
userOrder.TimeEnd = core2.FormatTime(res.TimeEnd) userOrder.TimeEnd = core2.FormatTime(res.TimeEnd)
switch res.TradeState { switch res.TradeState {
case CODE_TRADE_SUCCESS: case CODE_TRADE_SUCCESS:
userOrder.Status = 1 userOrder.Status = 1
case CODE_TRADE_REVOKED: case CODE_TRADE_REVOKED:
@ -270,7 +311,7 @@ func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) {
userOrder.Status = 5 userOrder.Status = 5
case CODE_TRADE_CLOSED: case CODE_TRADE_CLOSED:
userOrder.Status = 6 userOrder.Status = 6
default:
case CODE_TRADE_NOTPAY: // 超过期限,就关闭
userOrder.Status = 0 userOrder.Status = 0
} }
@ -281,7 +322,6 @@ func OrderQuery(outTradeNo string) (*pay.OrderQueryResponse, error) {
} }
func Close(outTradeNo string) error { func Close(outTradeNo string) error {
//client := wechat.NewClient(Appid, Mchid, ApiKey, true)
client, err := Client() client, err := Client()
if err != nil { if err != nil {
return err return err
@ -336,19 +376,19 @@ func Refund(reason, outTradeNo string) (*pay.RefundResponse, error) {
return nil, err return nil, err
} }
PutOrderChan(outTradeNo) // 退款查询
PutOrderDelayQueue(userOrder.Body, userOrder.OutTradeNo, userOrder.OpenId, int(userOrder.TotalFee), userOrder.Status, 5, 0) // 退款查询
return res, nil return res, nil
} }
func QueryRefund(outTradeNo string) (*pay.RefundQueryResponse, error) { func QueryRefund(outTradeNo string) (*pay.RefundQueryResponse, error) {
userOrder := new(models.UserOrder) userOrder := new(models.UserOrder)
exist, err := userOrder.GetByOutTradeNo(outTradeNo)
if err != nil {
return nil, err
}
if !exist {
return nil, errors.New("不存在改笔退款")
}
//exist, err := userOrder.GetByOutTradeNo(outTradeNo)
//if err != nil {
// return nil, err
//}
//if !exist {
// return nil, errors.New("不存在改笔退款")
//}
client, err := Client() client, err := Client()
res, err := pay.RefundQuery2(client, &pay.RefundQueryRequest{ res, err := pay.RefundQuery2(client, &pay.RefundQueryRequest{
@ -358,6 +398,8 @@ func QueryRefund(outTradeNo string) (*pay.RefundQueryResponse, error) {
}) })
//请求申请退款 //请求申请退款
if err != nil { if err != nil {
userOrder.ErrMsg = err.Error()
userOrder.UpdateErrByOutTradeNo(outTradeNo)
return nil, err return nil, err
} }

32
services/pay/refund.go

@ -1,32 +0,0 @@
package pay_service
//func BatchQueryRefundByUserId(userId int64) error {
// refunds := make([]*models.UserRefund, 0)
// if err := core.GetXormAuto().Where("status = 0 and user_id=?", userId).Find(&refunds); err != nil {
// return err
// }
// if err := batchQueryRefund(refunds); err != nil {
// return err
// }
// return nil
//}
//func BatchQueryRefundByActivityId(activityId int64) error {
// refunds := make([]*models.UserRefund, 0)
// if err := core.GetXormAuto().Where("status = 0 and user_id=?", activityId).Find(&refunds); err != nil {
// return err
// }
// if err := batchQueryRefund(refunds); err != nil {
// return err
// }
// return nil
//}
//
//func batchQueryRefund(refunds []*models.UserRefund) error {
// for _, refund := range refunds {
// _, err := QueryRefund(refund.OutTradeNo)
// if err != nil {
// return err
// }
// }
// return nil
//}

163
services/pay/transfer.go

@ -4,12 +4,106 @@ import (
"fmt" "fmt"
"github.com/chanxuehong/wechat/mch/mmpaymkttransfers" "github.com/chanxuehong/wechat/mch/mmpaymkttransfers"
"github.com/chanxuehong/wechat/mch/mmpaymkttransfers/promotion" "github.com/chanxuehong/wechat/mch/mmpaymkttransfers/promotion"
"go.uber.org/zap"
"hudongzhuanjia/logger"
"hudongzhuanjia/models" "hudongzhuanjia/models"
"hudongzhuanjia/utils" "hudongzhuanjia/utils"
"math"
"strconv" "strconv"
"time" "time"
) )
func init() {
go loopTransfer()
}
var transferDelayQueue = make(chan *transferDelayQueueParam, math.MaxInt8)
type transferDelayQueueParam struct {
Retries int `json:"retries"` // 尝试次数
Delay int `json:"delay"` // 延迟时间, 单位second
Amount int `json:"amount"` // 转账金额
Desc string `json:"desc"` // 转账描述
OpenId string `json:"open_id"` // 被转账人
PartnerTradeNo string `json:"partner_trade_no"` // 转账账单单号
}
func loopTransfer() {
//初始化
transfers, err := models.GetUserTransferByStatus(0, 1, 3)
if err != nil {
panic(err)
}
transferDelayQueue = make(chan *transferDelayQueueParam, math.MaxInt8)
for _, transfer := range transfers {
transferDelayQueue <- &transferDelayQueueParam{
Retries: 5,
Delay: 2 * 60,
Amount: transfer.PaymentAmount,
Desc: transfer.Desc,
OpenId: transfer.OpenId,
PartnerTradeNo: transfer.PartnerTradeNo,
}
}
defer func() {
if errRec := recover(); errRec != nil {
logger.Error("转账轮询 loop transfer panic", zap.Any("错误原因", errRec))
}
loopTransfer()
}()
for {
select {
case param, ok := <-transferDelayQueue:
if !ok {
panic("转账延迟通道异常关闭")
}
// 尝试次数
if param.Retries <= 0 {
logger.Info("微信转账尝试3次失败", zap.String("转账账单单号", param.PartnerTradeNo))
userTransfer := new(models.UserTransfer)
userTransfer.Status = 4
_, err = userTransfer.UpdateByPartnerTradeNo(param.PartnerTradeNo)
if err != nil {
logger.Info("微信转账更新状态失败", zap.String("失败原因", err.Error()),
zap.String("转账账单单号", param.PartnerTradeNo))
}
continue
} else {
param.Retries--
}
time.Sleep(time.Duration(param.Delay) * time.Second)
res, err := TransferInfo(param.PartnerTradeNo)
if err != nil {
logger.Error("微信转账查询出现的错误", zap.String("错误原因", err.Error()),
zap.String("转账账单", param.PartnerTradeNo))
transferDelayQueue <- param
continue
}
if res.Status == CODE_SUCCESS {
continue
} else if res.Status == CODE_TRANSFER_PROCESSING {
transferDelayQueue <- param
continue
} else {
//失败 --> 重新转账
_, err = Transfer(param.Desc, param.OpenId, param.PartnerTradeNo, param.Amount)
if err != nil {
logger.Error("微信转账出现的错误", zap.String("错误原因", err.Error()),
zap.String("转账账单", param.PartnerTradeNo))
}
transferDelayQueue <- param // 重新确认
continue
}
}
}
}
// 企业向微信用户个人付款(不支持沙箱环境) // 企业向微信用户个人付款(不支持沙箱环境)
type TransferResponse struct { type TransferResponse struct {
DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"` DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"`
@ -19,6 +113,23 @@ type TransferResponse struct {
PaymentTime string `xml:"payment_time,omitempty" json:"payment_time,omitempty"` PaymentTime string `xml:"payment_time,omitempty" json:"payment_time,omitempty"`
} }
func PutTransferDelayQueue(desc, openId, partnerTradeNo string, amount, retries, delay int) {
if retries <= 0 {
retries = 3
}
if delay == 0 {
delay = 30
}
transferDelayQueue <- &transferDelayQueueParam{
Retries: retries,
Delay: delay,
Amount: amount,
Desc: desc,
OpenId: openId,
PartnerTradeNo: partnerTradeNo,
}
}
func Transfer(desc, openId, partnerTradeNo string, amount int) (*TransferResponse, error) { func Transfer(desc, openId, partnerTradeNo string, amount int) (*TransferResponse, error) {
nonceStr := utils.RandomStr(32) nonceStr := utils.RandomStr(32)
@ -39,9 +150,13 @@ func Transfer(desc, openId, partnerTradeNo string, amount int) (*TransferRespons
client, err := Client() client, err := Client()
m, err := promotion.Transfers(client, body) m, err := promotion.Transfers(client, body)
// 记录错误信息
if err != nil { if err != nil {
transfer := new(models.UserTransfer)
transfer.UpdateErrMsg(partnerTradeNo, err.Error())
return nil, err return nil, err
} }
res := &TransferResponse{ res := &TransferResponse{
DeviceInfo: m["device_info"], DeviceInfo: m["device_info"],
NonceStr: m["nonce_str"], NonceStr: m["nonce_str"],
@ -49,10 +164,37 @@ func Transfer(desc, openId, partnerTradeNo string, amount int) (*TransferRespons
PaymentNo: m["payment_no"], PaymentNo: m["payment_no"],
PaymentTime: m["payment_time"], PaymentTime: m["payment_time"],
} }
// 获取某些信息
transfer := new(models.UserTransfer)
exist, err := transfer.GetByPartnerTradeNo(partnerTradeNo)
if err != nil {
return nil, err
}
transfer.Desc = desc
transfer.OpenId = openId
transfer.PartnerTradeNo = partnerTradeNo
transfer.PaymentAmount = amount
transfer.PaymentNo = res.PaymentNo
transfer.DeviceInfo = res.DeviceInfo
transfer.PaymentTime = res.PaymentTime
if !exist {
_, err = transfer.Add()
if err != nil {
return nil, err
}
} else {
_, err = transfer.UpdateByPartnerTradeNo(partnerTradeNo)
if err != nil {
return nil, err
}
}
return res, nil return res, nil
} }
type TransferInfoResponse struct { type TransferInfoResponse struct {
ErrCode string `json:"err_code"`
Status string `json:"status"` Status string `json:"status"`
Reason string `json:"reason"` Reason string `json:"reason"`
Openid string `json:"openid"` Openid string `json:"openid"`
@ -76,11 +218,13 @@ func TransferInfo(partnerTradeNo string) (*TransferInfoResponse, error) {
m, err := mmpaymkttransfers.GetTransferInfo(client, body) m, err := mmpaymkttransfers.GetTransferInfo(client, body)
if err != nil { if err != nil {
transfer := new(models.UserTransfer)
transfer.UpdateErrMsg(partnerTradeNo, err.Error())
return nil, err return nil, err
} }
amount, _ := strconv.Atoi(m["payment_amount"]) amount, _ := strconv.Atoi(m["payment_amount"])
resp := &TransferInfoResponse{
res := &TransferInfoResponse{
Status: m["status"], Status: m["status"],
Reason: m["reason"], Reason: m["reason"],
Openid: m["openid"], Openid: m["openid"],
@ -88,8 +232,23 @@ func TransferInfo(partnerTradeNo string) (*TransferInfoResponse, error) {
PaymentTime: m["payment_time"], PaymentTime: m["payment_time"],
TransferTime: m["transfer_time"], TransferTime: m["transfer_time"],
Desc: m["desc"], Desc: m["desc"],
ErrCode: m["err_code"],
}
transfer := new(models.UserTransfer)
if res.Status == CODE_SUCCESS {
transfer.Status = 2
} else if res.Status == CODE_TRANSFER_PROCESSING {
transfer.Status = 1
} else if res.Status == CODE_FAIL {
transfer.Status = 3
} }
return resp, nil
transfer.Reason = res.Reason
transfer.TransferTime = res.TransferTime
_, err = transfer.UpdateByPartnerTradeNo(partnerTradeNo)
if err != nil {
return nil, err
}
return res, nil
} }

26
test/pay_test.go

@ -2,8 +2,10 @@ package test
import ( import (
"fmt" "fmt"
"github.com/chanxuehong/wechat/mch/core"
pay_service "hudongzhuanjia/services/pay" pay_service "hudongzhuanjia/services/pay"
"testing" "testing"
"time"
) )
var openId = "o9XM41s_NN8Y0QK6_MbM-aYMV3TE" var openId = "o9XM41s_NN8Y0QK6_MbM-aYMV3TE"
@ -20,3 +22,27 @@ func TestSendRedPack(t *testing.T) {
fmt.Println(err) fmt.Println(err)
fmt.Printf("%+v\n", res) fmt.Printf("%+v\n", res)
} }
func TestQueryOrder(t *testing.T) {
//outTradeNo := "Dn13Gl6A6dB6aOae7syqtXSwUvCZ3mta"
outTradeNo := "jGrqipGJdcxQz4uwSTQqrtnJ4rJE6Mx9"
res, err := pay_service.OrderQuery(outTradeNo)
fmt.Println(err)
fmt.Printf("%+v\n", res)
}
func TestClose(t *testing.T) {
pay_service.Close("jGrqipGJdcxQz4uwSTQqrtnJ4rJE6Mx9")
}
func TestTimeExpire(t *testing.T) {
now := time.Now()
t1 := "202004174430"
t2 := core.FormatTime(time.Now())
t3, _ := core.ParseTime(t1)
fmt.Println(t1, t2)
fmt.Println(t1 > t2)
fmt.Println(t3.Unix() > now.Unix())
fmt.Println(t1, t2, core.FormatTime(t3))
fmt.Println(t3.Unix(), now.Unix())
}
Loading…
Cancel
Save