黄梓健 5 years ago
parent
commit
e6058504c1
  1. 2
      controllers/client/bully_screen.go
  2. 3
      controllers/client/lottery.go
  3. 2
      controllers/client/reward.go
  4. 6
      controllers/client/wx.go
  5. 2
      controllers/pc/activity.go
  6. 8
      libs/wechat/wx.go
  7. 32
      libs/wx/code.go
  8. 44
      libs/wx/params.go
  9. 70
      libs/wx/pay.go
  10. 9
      libs/wx/wx.go
  11. 16
      services/lottery/lottery.go
  12. 3
      services/pay/client.go
  13. 141
      services/pay/const.go
  14. 105
      services/pay/handle.go
  15. 101
      services/pay/order.go
  16. 16
      services/pay/order_test.go
  17. 17
      services/pay/transfer.go
  18. 2
      test/pay_test.go
  19. 67
      utils/define/define.go

2
controllers/client/bully_screen.go

@ -51,7 +51,7 @@ func (t *BullyScreenCtl) PaScreen() {
res["out_trade_no"] = ""
if activity.RehearsalId == 0 {
res, err = pay_service.UnifiedOrder("欧轩互动-霸屏支付", user.Openid, int64(amount*100), 1, user.Id,
activityId, time.Now().Add(24*time.Hour).Unix())
activityId, time.Now().Add(48*time.Hour).Unix())
t.CheckErr(err)
}

3
controllers/client/lottery.go

@ -93,8 +93,7 @@ func (t *LotteryCtl) Winners() {
t.CheckErr(err)
t.Assert(exist, code.MSG_LOTTERY_RULE_NOT_EXIST, "抽奖规则不存在")
result := make([]*LotteryUsersResult, 0)
err = models.GetLotteryUsersResultByLotteryDrawRecord(result, ladderId, activity.RehearsalId, ladder.RollNum)
result, err := lottery_service.GetLotteryUsersResultByRollNum(ladderId, activity.RehearsalId, ladder.RollNum)
t.CheckErr(err)
t.JSON(map[string]interface{}{
"total": len(result),

2
controllers/client/reward.go

@ -57,7 +57,7 @@ func (t *RewardCtl) Reward() {
res["out_trade_no"] = ""
if activity.RehearsalId == 0 || _type == 1 { // 直播不用彩排
res, err = pay_service.UnifiedOrder("欧轩互动-打赏支付", user.Openid, int64(amount*100), 2,
user.Id, activityId, time.Now().Add(24*time.Hour).Unix())
user.Id, activityId, time.Now().Add(48*time.Hour).Unix())
t.CheckErr(err)
}

6
controllers/client/wx.go

@ -2,10 +2,10 @@ package client
import (
"fmt"
"github.com/ouxuanserver/osmanthuswine/src/helper"
"hudongzhuanjia/controllers"
"hudongzhuanjia/libs/wx"
"hudongzhuanjia/utils"
"hudongzhuanjia/utils/define"
"time"
)
@ -29,7 +29,7 @@ var cache TicketCache
// 检测ticket是否过期
func (t *WxCtl) Ticket() {
url := t.MustGet("url")
nonceStr := helper.CreateUUID()
nonceStr := utils.RandomStr(32)
timestamp := time.Now().Unix()
if cache.TokenExpired <= time.Now().Unix() {
@ -57,7 +57,7 @@ func (t *WxCtl) Ticket() {
"noncestr": nonceStr,
"timestamp": timestamp,
"ticket": cache.Ticket,
"appid": wx.Appid,
"appid": define.AppId,
})
}

2
controllers/pc/activity.go

@ -52,7 +52,7 @@ func (t *ActivityCtl) StartActivity() {
activity.Status = define.StatusRunning
activity.UpdatedAt = time.Now()
// todo: 校验
_, err = models.Update(activity.Id, "status", "rehearsal_id")
_, err = models.Update(activity.Id, activity, "status", "rehearsal_id")
t.CheckErr(err)
t.JSON(map[string]interface{}{
"rehearsal_id": activity.RehearsalId,

8
libs/wechat/wx.go

@ -3,14 +3,10 @@ package wechat
import (
mpoauth2 "github.com/chanxuehong/wechat/mp/oauth2"
"github.com/chanxuehong/wechat/oauth2"
"hudongzhuanjia/utils/define"
)
var (
Appid = "wx7b0bcf476552c5e9"
Secret = "f6aabdd40ea25272f4442603a7dc8028"
)
var Endpoint = mpoauth2.NewEndpoint(Appid, Secret)
var Endpoint = mpoauth2.NewEndpoint(define.AppId, define.Secret)
func GetToken(code string) (*oauth2.Token, error) {
client := oauth2.Client{

32
libs/wx/code.go

@ -1,32 +0,0 @@
package wx
const CODE_SUCCESS = "SUCCESS" // 成功
const CODE_FAIL = "FAIL" // 失败
const CODE_NOTPAY = "NOTPAY" // 未支付
const CODE_CHANGE = "CHANGE" // 退款异常
const CODE_REFUNDCLOSE = "REFUNDCLOSE" // 退款关闭
const CODE_ERROR = "ERROR" // 业务错误
const CODE_INVALID_REQUEST = "INVALID_REQUEST" // 无效请求
const CODE_NOAUTH = "NOAUTH" // 异常IP请求不予受理
const CODE_NOTENOUGH = "NOTENOUGH" // 余额不足
const CODE_ORDERPAID = "ORDERPAID" // 订单已支付
const CODE_ORDERCLOSED = "ORDERCLOSED" // 订单已关闭
const CODE_SYSTEMERROR = "SYSTEMERROR" // 系统错误
const CODE_APPID_NOT_EXIST = "APPID_NOT_EXIST" // APPID不存在
const CODE_MCHID_NOT_EXIST = "MCHID_NOT_EXIST" // MCHID不存在
const CODE_APPID_MCHID_NOT_MATCH = "APPID_MCHID_NOT_MATCH" // APPID MCHID 不匹配
const CODE_LACK_PARAMS = "LACK_PARAMS" // 缺少参数
const CODE_OUT_TRADE_NO_USED = "OUT_TRADE_NO_USED" // 商户订单号重复
const CODE_SIGNERROR = "SIGNERROR" // 签名错误
const CODE_XML_FORMAT_ERROR = "XML_FORMAT_ERROR" // xml格式错误
const CODE_REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD" // 请使用post请求方法
const CODE_POST_DATA_EMPTY = "POST_DATA_EMPTY" // post数据为空
const CODE_NOT_UTF8 = "NOT_UTF8" // 编码错误
const CODE_ORDERNOTEXIST = "ORDERNOTEXIST" // 交易订单号不存在
const CODE_BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY" // 退款业务流程错误,需要商户触发重试来解决
const CODE_TRADE_OVERDUE = "TRADE_OVERDUE" // 订单已经超过退款期限
const CODE_USER_ACCOUNT_ABNORMAL = "USER_ACCOUNT_ABNORMAL" // 退款请求失败用户帐号注销
const CODE_INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH" // 无效请求过多
const CODE_INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID" // 无效transaction_id
const CODE_PARAM_ERROR = "PARAM_ERROR" // 参数错误
const CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制

44
libs/wx/params.go

@ -6,17 +6,17 @@ import (
"hudongzhuanjia/utils/define"
)
var (
WxCertPath = `./cacert/apiclient_cert.pem`
WxKeyPath = `./cacert/apiclient_key.pem`
WxCaPath = `./cacert/rootca.pem`
Appid = "wx7b0bcf476552c5e9"
Secret = "f6aabdd40ea25272f4442603a7dc8028"
Mchid = `1394404502`
ApiKey = `2c82c64ceec6ba89ffc9f593c671a12f`
mainHost = `https://api.mch.weixin.qq.com`
backHost = `https://api2.mch.weixin.qq.com`
)
//var (
// WxCertPath = `./cacert/apiclient_cert.pem`
// WxKeyPath = `./cacert/apiclient_key.pem`
// WxCaPath = `./cacert/rootca.pem`
// Appid = "wx7b0bcf476552c5e9"
// Secret = "f6aabdd40ea25272f4442603a7dc8028"
// Mchid = `1394404502`
// ApiKey = `2c82c64ceec6ba89ffc9f593c671a12f`
// mainHost = `https://api.mch.weixin.qq.com`
// backHost = `https://api2.mch.weixin.qq.com`
//)
var (
RedirectUri = "http://api.hudongzhuanjia.com/"
@ -31,17 +31,17 @@ var (
)
var (
NotifyURL = fmt.Sprintf("%s/wechat/callback", define.HOST) // 微信回调通知
UnifiedOrderURL = fmt.Sprintf("%s/pay/unifiedorder", mainHost) // 统一下单url
QueryOrderURL = fmt.Sprintf("%s/pay/orderquery", mainHost) // 微信查询订单
CloseOrderURL = fmt.Sprintf("%s/pay/closeorder", mainHost) // 微信关闭订单
RefundURL = fmt.Sprintf("%s/secapi/pay/refund", mainHost) // 微信退款
RefundQueryURL = fmt.Sprintf("%s/pay/refundquery", mainHost) // 微信查询退款
DownloadBillURL = fmt.Sprintf("%s/pay/downloadbill", mainHost) // 微信下载账单
DownloadFundFlowURL = fmt.Sprintf("%s/pay/downloadfundflow", mainHost)
TransfersURL = fmt.Sprintf("%s/mmpaymkttransfers/promotion/transfers", mainHost)
SendRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/sendredpack", mainHost)
QueryRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/gethbinfo", mainHost)
NotifyURL = fmt.Sprintf("%s/wechat/callback", define.HOST) // 微信回调通知
UnifiedOrderURL = fmt.Sprintf("%s/pay/unifiedorder", define.WxHost) // 统一下单url
QueryOrderURL = fmt.Sprintf("%s/pay/orderquery", define.WxHost) // 微信查询订单
CloseOrderURL = fmt.Sprintf("%s/pay/closeorder", define.WxHost) // 微信关闭订单
RefundURL = fmt.Sprintf("%s/secapi/pay/refund", define.WxHost) // 微信退款
RefundQueryURL = fmt.Sprintf("%s/pay/refundquery", define.WxHost) // 微信查询退款
DownloadBillURL = fmt.Sprintf("%s/pay/downloadbill", define.WxHost) // 微信下载账单
DownloadFundFlowURL = fmt.Sprintf("%s/pay/downloadfundflow", define.WxHost)
TransfersURL = fmt.Sprintf("%s/mmpaymkttransfers/promotion/transfers", define.WxHost)
SendRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/sendredpack", define.WxHost)
QueryRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/gethbinfo", define.WxHost)
)
type CommonReturn struct {

70
libs/wx/pay.go

@ -3,9 +3,9 @@ package wx
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/xml"
"fmt"
"hudongzhuanjia/utils/define"
"io/ioutil"
"net/http"
)
@ -22,28 +22,28 @@ var _tlsConfig *tls.Config
//var WxClient = NewClient()
func getTLSConfig() (*tls.Config, error) {
if _tlsConfig != nil {
return _tlsConfig, nil
}
// load cert
cert, err := tls.LoadX509KeyPair(WxCertPath, WxKeyPath)
if err != nil {
return nil, err
}
// load root ca
caData, err := ioutil.ReadFile(WxCaPath)
if err != nil {
return nil, err
}
pool := x509.NewCertPool()
pool.AppendCertsFromPEM(caData)
_tlsConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: pool,
}
return _tlsConfig, nil
}
//func getTLSConfig() (*tls.Config, error) {
// if _tlsConfig != nil {
// return _tlsConfig, nil
// }
// // load cert
// cert, err := tls.LoadX509KeyPair(WxCertPath, WxKeyPath)
// if err != nil {
// return nil, err
// }
// // load root ca
// caData, err := ioutil.ReadFile(WxCaPath)
// if err != nil {
// return nil, err
// }
// pool := x509.NewCertPool()
// pool.AppendCertsFromPEM(caData)
// _tlsConfig = &tls.Config{
// Certificates: []tls.Certificate{cert},
// RootCAs: pool,
// }
// return _tlsConfig, nil
//}
type Client struct {
AppId string
@ -82,10 +82,10 @@ func (w *Client) UnifiedOrder(param *UnifiedOrderParam) (*UnifiedOrderResult, er
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
@ -113,10 +113,10 @@ func (w *Client) QueryOrder(param *QueryOrderParam) (*QueryOrderResult, error) {
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, return_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
return res, nil
@ -143,10 +143,10 @@ func (w *Client) CloseOrder(param *CloseOrderParam) (*CloseOrderResult, error) {
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, return_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
@ -174,10 +174,10 @@ func (w *Client) Refund(param *RefundParam) (*RefundResult, error) {
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, return_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
@ -205,10 +205,10 @@ func (w *Client) RefundQuery(param *RefundQueryParam) (*RefundQueryResult, error
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, return_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
return res, nil
@ -239,10 +239,10 @@ func (w *Client) SendRedPack(param *RedPackParam) (*RedPackResult, error) {
if err != nil {
return nil, err
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return res, fmt.Errorf("network error, return_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode != CODE_SUCCESS {
if res.ResultCode != define.CODE_SUCCESS {
return res, fmt.Errorf("trade error, err_code: %v and err_code_des: %v", res.ErrCode, res.ErrCodeDes)
}
return res, nil

9
libs/wx/wx.go

@ -4,20 +4,21 @@ import (
"fmt"
"github.com/kirinlabs/HttpRequest"
"github.com/ouxuanserver/osmanthuswine/src/helper"
"hudongzhuanjia/utils/define"
"net/url"
)
func GetCodeUrl() string {
uid := helper.CreateUUID()
return fmt.Sprintf(CodeUrl, Appid, url.PathEscape(RedirectUri), uid)
return fmt.Sprintf(CodeUrl, define.AppId, url.PathEscape(RedirectUri), uid)
}
func GetAccessTokenUrl(code string) string {
return fmt.Sprintf(AccessTokenUrl, Appid, Secret, code)
return fmt.Sprintf(AccessTokenUrl, define.AppId, define.Secret, code)
}
func GetRefreshTokenUrl(refreshToken string) string {
return fmt.Sprintf(RefreshTokenUrl, Appid, refreshToken)
return fmt.Sprintf(RefreshTokenUrl, define.AppId, refreshToken)
}
func GetAuthUrl(accessToken string, openid string) string {
@ -33,7 +34,7 @@ func GetTicketUrl(ticketToken string) string {
}
func GetTicketTokenUrl() string {
return fmt.Sprintf(TicketTokenUrl, Appid, Secret)
return fmt.Sprintf(TicketTokenUrl, define.AppId, define.Secret)
}
///

16
services/lottery/lottery.go

@ -142,6 +142,20 @@ type LotteryUsersResult struct {
Avatar string `json:"avatar"`
}
func GetLotteryUsersResultByRollNum(ladderId, rehearsalId interface{}, rollNum int) ([]*LotteryUsersResult, error) {
users := make([]*LotteryUsersResult, 0)
session := core.GetXormAuto().Table(new(models.LotteryDrawRecord)).Alias("r").
Join("LEFT", new(models.User).Alias("u"), "u.id=r.user_id").
Where("r.is_delete=0 and r.lottery_draw_rule_ladder_id=? and "+
"r.rehearsal_id=?", ladderId, rehearsalId)
defer session.Close()
if rollNum > 0 {
session = session.Where("roll_num=?", rollNum)
}
err := session.Find(&users)
return users, err
}
func GetLotteryUsersResult(areaId, activityId, rehearsalId interface{}, ids []int64) ([]*LotteryUsersResult, error) {
result := make([]*LotteryUsersResult, 0)
session := core.GetXormAuto().Table(new(models.SignHistory)).Alias("h").
@ -169,7 +183,7 @@ type WinnersResult struct {
func GetWinnersResult(ruleId, rehearsalId interface{}) ([]*WinnersResult, error) {
result := make([]*WinnersResult, 0)
err := core.GetXormAuto().Table("ox_lottery_draw_record").Alias("record").
err := core.GetXormAuto().Table(new(models.LotteryDrawRecord)).Alias("record").
Join("LEFT", new(models.User).Alias("user"), "user.id=record.user_id and user.is_delete=0").
Where("record.is_delete=0 and record.lottery_draw_rule_id=? and record.rehearsal_id=?", ruleId, rehearsalId).
Find(&result)

3
services/pay/client.go

@ -5,6 +5,7 @@ import (
"crypto/x509"
"fmt"
"github.com/chanxuehong/wechat/mch/core"
"hudongzhuanjia/utils/define"
"net/http"
)
@ -44,5 +45,5 @@ func Client() (*core.Client, error) {
},
}
return core.NewClient(Appid, Mchid, ApiKey, httpClient), nil
return core.NewSubMchClient(define.AppId, define.MchId, define.ApiKey, "", define.SubMchId, httpClient), nil
}

141
services/pay/const.go

@ -1,78 +1,79 @@
package pay_service
import (
"fmt"
"hudongzhuanjia/utils/define"
)
import ()
var (
WxCertPath = `./cacert/apiclient_cert.pem`
WxKeyPath = `./cacert/apiclient_key.pem`
WxCaPath = `./cacert/rootca.pem`
Appid = "wx7b0bcf476552c5e9"
Secret = "f6aabdd40ea25272f4442603a7dc8028"
Mchid = `1394404502`
ApiKey = `2c82c64ceec6ba89ffc9f593c671a12f`
ClientIp = `123.207.246.51`
mainHost = `https://api.mch.weixin.qq.com`
backHost = `https://api2.mch.weixin.qq.com`
)
//var (
// WxCertPath = `./cacert/apiclient_cert.pem`
// WxKeyPath = `./cacert/apiclient_key.pem`
// WxCaPath = `./cacert/rootca.pem`
// //MchId = `1394404502`
// //AppId = "wx7b0bcf476552c5e9"
// Secret = "f6aabdd40ea25272f4442603a7dc8028"
// AppId = `wx662a1633304bfd42`
// MchId = `1441266702`
// SubMchId = `1594049151`
// ApiKey = `5x201c8zn43cg675204594cab5423320`
// //ApiKey = `2c82c64ceec6ba89ffc9f593c671a12f`
// ClientIp = `123.207.246.51`
// mainHost = `https://api.mch.weixin.qq.com`
// backHost = `https://api2.mch.weixin.qq.com`
//)
var (
NotifyURL = fmt.Sprintf("%s/wechat/callback", define.HOST) // 微信回调通知
UnifiedOrderURL = fmt.Sprintf("%s/pay/unifiedorder", mainHost) // 统一下单url
QueryOrderURL = fmt.Sprintf("%s/pay/orderquery", mainHost) // 微信查询订单
CloseOrderURL = fmt.Sprintf("%s/pay/closeorder", mainHost) // 微信关闭订单
RefundURL = fmt.Sprintf("%s/secapi/pay/refund", mainHost) // 微信退款
RefundQueryURL = fmt.Sprintf("%s/pay/refundquery", mainHost) // 微信查询退款
DownloadBillURL = fmt.Sprintf("%s/pay/downloadbill", mainHost) // 微信下载账单
DownloadFundFlowURL = fmt.Sprintf("%s/pay/downloadfundflow", mainHost)
TransfersURL = fmt.Sprintf("%s/mmpaymkttransfers/promotion/transfers", mainHost)
SendRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/sendredpack", mainHost)
QueryRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/gethbinfo", mainHost)
)
//var (
// NotifyURL = fmt.Sprintf("%s/wechat/callback", define.HOST) // 微信回调通知
// UnifiedOrderURL = fmt.Sprintf("%s/pay/unifiedorder", mainHost) // 统一下单url
// QueryOrderURL = fmt.Sprintf("%s/pay/orderquery", mainHost) // 微信查询订单
// CloseOrderURL = fmt.Sprintf("%s/pay/closeorder", mainHost) // 微信关闭订单
// RefundURL = fmt.Sprintf("%s/secapi/pay/refund", mainHost) // 微信退款
// RefundQueryURL = fmt.Sprintf("%s/pay/refundquery", mainHost) // 微信查询退款
// DownloadBillURL = fmt.Sprintf("%s/pay/downloadbill", mainHost) // 微信下载账单
// DownloadFundFlowURL = fmt.Sprintf("%s/pay/downloadfundflow", mainHost)
// TransfersURL = fmt.Sprintf("%s/mmpaymkttransfers/promotion/transfers", mainHost)
// SendRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/sendredpack", mainHost)
// QueryRedPackURL = fmt.Sprintf("%s/mmpaymkttransfers/gethbinfo", mainHost)
//)
const (
CODE_SUCCESS = "SUCCESS" // 成功
CODE_FAIL = "FAIL" // 失败
CODE_NOTPAY = "NOTPAY" // 未支付
CODE_CHANGE = "CHANGE" // 退款异常
CODE_REFUNDCLOSE = "REFUNDCLOSE" // 退款关闭
CODE_ERROR = "ERROR" // 业务错误
CODE_INVALID_REQUEST = "INVALID_REQUEST" // 无效请求
CODE_NOAUTH = "NOAUTH" // 异常IP请求不予受理
CODE_NOTENOUGH = "NOTENOUGH" // 余额不足
CODE_ORDERPAID = "ORDERPAID" // 订单已支付
CODE_ORDERCLOSED = "ORDERCLOSED" // 订单已关闭
CODE_SYSTEMERROR = "SYSTEMERROR" // 系统错误
CODE_APPID_NOT_EXIST = "APPID_NOT_EXIST" // APPID不存在
CODE_MCHID_NOT_EXIST = "MCHID_NOT_EXIST" // MCHID不存在
CODE_APPID_MCHID_NOT_MATCH = "APPID_MCHID_NOT_MATCH" // APPID MCHID 不匹配
CODE_LACK_PARAMS = "LACK_PARAMS" // 缺少参数
CODE_OUT_TRADE_NO_USED = "OUT_TRADE_NO_USED" // 商户订单号重复
CODE_SIGNERROR = "SIGNERROR" // 签名错误
CODE_XML_FORMAT_ERROR = "XML_FORMAT_ERROR" // xml格式错误
CODE_REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD" // 请使用post请求方法
CODE_POST_DATA_EMPTY = "POST_DATA_EMPTY" // post数据为空
CODE_NOT_UTF8 = "NOT_UTF8" // 编码错误
CODE_ORDERNOTEXIST = "ORDERNOTEXIST" // 交易订单号不存在
CODE_BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY" // 退款业务流程错误,需要商户触发重试来解决
CODE_TRADE_OVERDUE = "TRADE_OVERDUE" // 订单已经超过退款期限
CODE_USER_ACCOUNT_ABNORMAL = "USER_ACCOUNT_ABNORMAL" // 退款请求失败用户帐号注销
CODE_INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH" // 无效请求过多
CODE_INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID" // 无效transaction_id
CODE_PARAM_ERROR = "PARAM_ERROR" // 参数错误
CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制
CODE_TRADE_SUCCESS = "SUCCESS" // 交易成功
CODE_TRADE_REFUND = "REFUND" // 转入退款
CODE_TRADE_NOTPAY = "NOTPAY" // 尚未支付
CODE_TRADE_CLOSED = "CLOSED" // 已关闭
CODE_TRADE_REVOKED = "REVOKED" // 已撤销
CODE_TRADE_USERPAYING = "USERPAYING" // 用户支付中
CODE_TRADE_PAYERROR = "PAYERROR" // 支付失败
CODE_TRANSFER_PROCESSING = "PROCESSING" // 转账处理中
CODE_TRANSFER_NOT_FOUND = "NOT_FOUND" // 账单不见了
)
//const (
// CODE_SUCCESS = "SUCCESS" // 成功
// CODE_FAIL = "FAIL" // 失败
// CODE_NOTPAY = "NOTPAY" // 未支付
// CODE_CHANGE = "CHANGE" // 退款异常
// CODE_REFUNDCLOSE = "REFUNDCLOSE" // 退款关闭
// CODE_ERROR = "ERROR" // 业务错误
// CODE_INVALID_REQUEST = "INVALID_REQUEST" // 无效请求
// CODE_NOAUTH = "NOAUTH" // 异常IP请求不予受理
// CODE_NOTENOUGH = "NOTENOUGH" // 余额不足
// CODE_ORDERPAID = "ORDERPAID" // 订单已支付
// CODE_ORDERCLOSED = "ORDERCLOSED" // 订单已关闭
// CODE_SYSTEMERROR = "SYSTEMERROR" // 系统错误
// CODE_APPID_NOT_EXIST = "APPID_NOT_EXIST" // APPID不存在
// CODE_MCHID_NOT_EXIST = "MCHID_NOT_EXIST" // MCHID不存在
// CODE_APPID_MCHID_NOT_MATCH = "APPID_MCHID_NOT_MATCH" // APPID MCHID 不匹配
// CODE_LACK_PARAMS = "LACK_PARAMS" // 缺少参数
// CODE_OUT_TRADE_NO_USED = "OUT_TRADE_NO_USED" // 商户订单号重复
// CODE_SIGNERROR = "SIGNERROR" // 签名错误
// CODE_XML_FORMAT_ERROR = "XML_FORMAT_ERROR" // xml格式错误
// CODE_REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD" // 请使用post请求方法
// CODE_POST_DATA_EMPTY = "POST_DATA_EMPTY" // post数据为空
// CODE_NOT_UTF8 = "NOT_UTF8" // 编码错误
// CODE_ORDERNOTEXIST = "ORDERNOTEXIST" // 交易订单号不存在
// CODE_BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY" // 退款业务流程错误,需要商户触发重试来解决
// CODE_TRADE_OVERDUE = "TRADE_OVERDUE" // 订单已经超过退款期限
// CODE_USER_ACCOUNT_ABNORMAL = "USER_ACCOUNT_ABNORMAL" // 退款请求失败用户帐号注销
// CODE_INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH" // 无效请求过多
// CODE_INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID" // 无效transaction_id
// CODE_PARAM_ERROR = "PARAM_ERROR" // 参数错误
// CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制
// CODE_TRADE_SUCCESS = "SUCCESS" // 交易成功
// CODE_TRADE_REFUND = "REFUND" // 转入退款
// CODE_TRADE_NOTPAY = "NOTPAY" // 尚未支付
// CODE_TRADE_CLOSED = "CLOSED" // 已关闭
// CODE_TRADE_REVOKED = "REVOKED" // 已撤销
// CODE_TRADE_USERPAYING = "USERPAYING" // 用户支付中
// CODE_TRADE_PAYERROR = "PAYERROR" // 支付失败
// CODE_TRANSFER_PROCESSING = "PROCESSING" // 转账处理中
// CODE_TRANSFER_NOT_FOUND = "NOT_FOUND" // 账单不见了
//)
type CommonReturn struct {
ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`

105
services/pay/handle.go

@ -6,12 +6,95 @@ import (
"hudongzhuanjia/logger"
"hudongzhuanjia/models"
im_service "hudongzhuanjia/services/im"
"hudongzhuanjia/utils/define"
"math"
"time"
)
//处理支付成功之后的回调问题
func init() {
go loopUnifiedOrder()
}
var orderDelayQueue = make(chan *models.UserOrder, math.MaxInt8)
func PutOrderDelayQueue(order *models.UserOrder) {
orderDelayQueue <- order
}
func loopUnifiedOrder() {
orders, err := models.GetUserOrdersByStatus(0, 3)
if err != nil {
panic(err)
}
for _, order := range orders {
PutOrderDelayQueue(order)
}
defer func() {
if err := recover(); err != nil {
logger.Error("订单轮询查询: panic 恢复错误", err)
}
// 重启
time.Sleep(5 * time.Second)
loopUnifiedOrder()
}()
for {
select {
case order, ok := <-orderDelayQueue:
if !ok {
panic("通道异常关闭")
}
if order.ExpireAt <= time.Now().Unix() { // 订单超时
if order.Status == 0 {
err = Close(order.OutTradeNo) // 超时关闭订单
if err != nil {
logger.Error("订单关闭出现错误: 错误原因->", err)
}
order.Status = 5
go HandleFailed(order)
}
continue
}
// 直播红包
if order.Status == 0 {
res, err := OrderQuery(order.OutTradeNo)
if err != nil {
logger.Error("查询订单出现错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
orderDelayQueue <- order // 重新进入队列
continue
}
if res["trade_state"] == define.CODE_TRADE_SUCCESS {
go HandleSuccess(order)
} else if res["trade_state"] == define.CODE_TRADE_REFUND {
order.Status = 3
orderDelayQueue <- order
continue
} else {
orderDelayQueue <- order
continue
}
} else if order.Status == 3 {
res, err := QueryRefund(order.OutTradeNo)
if err != nil {
logger.Error("退款订单查询错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
continue
}
order.RefundAccount = res.RefundList[0].RefundAccount
order.RefundRecvAccount = res.RefundList[0].RefundRecvAccout
order.Status = 4
_, err = models.Update(order.Id, order, "refund_account", "refund_recv_account", "status")
if err != nil {
logger.Error("退款状态改变错误: 错误原因-->", err, "交易订单号-->", order.OutTradeNo)
continue
}
}
}
}
}
//处理支付成功之后的回调问题
func HandleSuccess(order *models.UserOrder) error {
if order.GoodType == 4 { // 直播商品
customerOrder := new(models.CustomerOrder)
@ -186,3 +269,21 @@ func HandleFailed(order *models.UserOrder) error {
}
return nil
}
// 定时任务
// 1个小时查询一次
func HandleTicker() {
defer func() {
if err := recover(); err != nil {
logger.Error("定时任务错误原因", err)
}
HandleTicker()
}()
ticker := time.NewTicker(1 * time.Hour)
for {
select {
case <-ticker.C:
}
}
}

101
services/pay/order.go

@ -8,96 +8,13 @@ import (
"hudongzhuanjia/logger"
"hudongzhuanjia/models"
"hudongzhuanjia/utils"
"hudongzhuanjia/utils/define"
"io"
"io/ioutil"
"math"
"strconv"
"time"
)
func init() {
go loopUnifiedOrder()
}
var orderDelayQueue = make(chan *models.UserOrder, math.MaxInt8)
func PutOrderDelayQueue(order *models.UserOrder) {
orderDelayQueue <- order
}
func loopUnifiedOrder() {
orders, err := models.GetUserOrdersByStatus(0, 3)
if err != nil {
panic(err)
}
for _, order := range orders {
PutOrderDelayQueue(order)
}
defer func() {
if err := recover(); err != nil {
logger.Error("订单轮询查询: panic 恢复错误", err)
}
// 重启
time.Sleep(5 * time.Second)
loopUnifiedOrder()
}()
for {
select {
case order, ok := <-orderDelayQueue:
if !ok {
panic("通道异常关闭")
}
if order.ExpireAt <= time.Now().Unix() { // 订单超时
if order.Status == 0 {
err = Close(order.OutTradeNo) // 超时关闭订单
if err != nil {
logger.Error("订单关闭出现错误: 错误原因->", err)
}
order.Status = 5
go HandleFailed(order)
}
continue
}
if order.Status == 0 {
res, err := OrderQuery(order.OutTradeNo)
if err != nil {
logger.Error("查询订单出现错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
orderDelayQueue <- order // 重新进入队列
continue
}
if res["trade_state"] == CODE_TRADE_SUCCESS {
go HandleSuccess(order)
} else if res["trade_state"] == CODE_TRADE_REFUND {
order.Status = 3
orderDelayQueue <- order
continue
} else {
orderDelayQueue <- order
continue
}
} else if order.Status == 3 {
res, err := QueryRefund(order.OutTradeNo)
if err != nil {
logger.Error("退款订单查询错误: 错误原因-->", err.Error(), "交易订单号-->", order.OutTradeNo)
continue
}
order.RefundAccount = res.RefundList[0].RefundAccount
order.RefundRecvAccount = res.RefundList[0].RefundRecvAccout
order.Status = 4
_, err = models.Update(order.Id, order, "refund_account", "refund_recv_account", "status")
if err != nil {
logger.Error("退款状态改变错误: 错误原因-->", err, "交易订单号-->", order.OutTradeNo)
continue
}
}
}
}
}
const CallbackOrderUrl = "https://api.ouxuanhudong.com/PcClient/common/WeChatOauthCtl/callbackOrder"
func UnifiedOrder(content, openId string, fee, goodType, userId, activityId, expireAt int64) (map[string]interface{}, error) {
@ -114,10 +31,9 @@ func UnifiedOrder(content, openId string, fee, goodType, userId, activityId, exp
body["total_fee"] = fmt.Sprint(fee)
body["notify_url"] = CallbackOrderUrl
body["trade_type"] = "JSAPI"
body["device_info"] = "WEB"
body["nonce_str"] = nonceStr
body["sign_type"] = pay_core.SignType_MD5
body["open_id"] = openId
body["openid"] = openId
body["time_expire"] = pay_core.FormatTime(time.Unix(expireAt, 0))
resp, err := pay.UnifiedOrder(client, body)
@ -127,7 +43,6 @@ func UnifiedOrder(content, openId string, fee, goodType, userId, activityId, exp
// 记录这次订单
userOrder := new(models.UserOrder)
userOrder.DeviceInfo = "WEB"
userOrder.Body = content
userOrder.UserId = userId
userOrder.ActivityId = activityId
@ -147,11 +62,11 @@ func UnifiedOrder(content, openId string, fee, goodType, userId, activityId, exp
//获取H5支付需要的paySign
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
pac := "prepay_id=" + resp["prepay_id"]
paySign := pay_core.JsapiSign(client.AppId(), timestamp, nonceStr, pac, pay_core.SignType_MD5, ApiKey)
paySign := pay_core.JsapiSign(client.AppId(), timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
go PutOrderDelayQueue(userOrder)
return map[string]interface{}{
"appid": Appid,
"appid": client.AppId(),
"timestamp": timestamp,
"nonce_str": nonceStr,
"package": pac,
@ -176,10 +91,10 @@ func ReOrder(outTradeNo string) (map[string]interface{}, error) {
nonceStr := utils.RandomStr(32)
//获取H5支付需要的paySign
pac := "prepay_id=" + userOrder.PrepayId
paySign := pay_core.JsapiSign(Appid, timestamp, nonceStr, pac, pay_core.SignType_MD5, ApiKey)
paySign := pay_core.JsapiSign(define.AppId, timestamp, nonceStr, pac, pay_core.SignType_MD5, define.ApiKey)
go PutOrderDelayQueue(userOrder)
return map[string]interface{}{
"appid": Appid,
"appid": define.AppId,
"timestamp": timestamp,
"nonce_str": nonceStr,
"package": pac,
@ -241,11 +156,11 @@ func NotifyOrder(w io.Reader) (order *models.UserOrder, err error) {
return
}
if res.ReturnCode != CODE_SUCCESS {
if res.ReturnCode != define.CODE_SUCCESS {
return nil, fmt.Errorf("network error, retrun_code: %+v and return_msg: %+v", res.ReturnCode, res.ReturnMsg)
}
if res.ResultCode == CODE_SUCCESS && res.TradeType == CODE_TRADE_SUCCESS {
if res.ResultCode == define.CODE_SUCCESS && res.TradeType == define.CODE_TRADE_SUCCESS {
userOrder := new(models.UserOrder)
userOrder.TransactionId = res.TransactionId
userOrder.Status = 1

16
services/pay/order_test.go

@ -0,0 +1,16 @@
package pay_service
import (
"fmt"
"testing"
"time"
)
func TestUnifiedOrder(t *testing.T) {
res, err := UnifiedOrder("欧轩互动测试", "o9XM41s_NN8Y0QK6_MbM-aYMV3TE",
2, 1, 1, 101, time.Now().Add(1*time.Hour).Unix())
if err != nil {
t.Error(err)
}
fmt.Println(res)
}

17
services/pay/transfer.go

@ -8,6 +8,7 @@ import (
"hudongzhuanjia/logger"
"hudongzhuanjia/models"
"hudongzhuanjia/utils"
"hudongzhuanjia/utils/define"
"math"
"strconv"
"time"
@ -89,9 +90,9 @@ func loopTransfer() {
continue
}
if res.Status == CODE_SUCCESS {
if res.Status == define.CODE_SUCCESS {
continue
} else if res.Status == CODE_TRANSFER_PROCESSING {
} else if res.Status == define.CODE_TRANSFER_PROCESSING {
transferDelayQueue <- param
continue
} else {
@ -150,8 +151,8 @@ func Transfer(desc, openId, partnerTradeNo string, amount int) (*TransferRespons
body["check_name"] = "NO_CHECK" // NO_CHECK:不校验真实姓名 , FORCE_CHECK:强校验真实姓名
body["amount"] = fmt.Sprintf("%d", amount) // 企业付款金额,单位为分
body["desc"] = desc // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
body["mchid"] = Mchid
body["mch_appid"] = Appid
body["mchid"] = define.MchId
body["mch_appid"] = define.AppId
client, err := Client()
m, err := promotion.Transfers(client, body)
@ -240,11 +241,11 @@ func TransferInfo(partnerTradeNo string) (*TransferInfoResponse, error) {
ErrCode: m["err_code"],
}
transfer := new(models.UserTransfer)
if res.Status == CODE_SUCCESS {
if res.Status == define.CODE_SUCCESS {
transfer.Status = 2
} else if res.Status == CODE_TRANSFER_PROCESSING {
} else if res.Status == define.CODE_TRANSFER_PROCESSING {
transfer.Status = 1
} else if res.Status == CODE_FAIL {
} else if res.Status == define.CODE_FAIL {
transfer.Status = 3
}
transfer.Reason = res.Reason
@ -285,7 +286,7 @@ func SendRedPack(sendName, openId, wishing, actName, remark string, totalAmount,
body["total_amount"] = fmt.Sprintf("%d", totalAmount)
body["total_num"] = fmt.Sprintf("%d", totalNum)
body["wishing"] = wishing
body["client_ip"] = ClientIp
body["client_ip"] = define.ClientIp
body["act_name"] = actName
body["remark"] = remark
body["scene_id"] = fmt.Sprintf("PRODUCT_%d", scene)

2
test/pay_test.go

@ -34,7 +34,7 @@ func TestQueryOrder(t *testing.T) {
outTradeNo := "6PM9n5WDSX47frNfQ9OxWEKe8u6ChBos"
res, err := pay_service.OrderQuery(outTradeNo)
fmt.Println(err)
fmt.Printf("%+v\n", res.Query)
fmt.Printf("%+v\n", res)
}
func TestClose(t *testing.T) {

67
utils/define/define.go

@ -1,7 +1,5 @@
package define
import "time"
const TimeFormat = "2006-01-01 15:04:05"
const (
@ -86,5 +84,68 @@ const (
TYPE_ENTRYPEOPLE = "entry_people"
)
var DefaultTime = time.Date(1970, 1, 1, 8, 0, 0, 0, time.Local)
// 固定长度
var DefaultOrderNo = 10000000000
// 微信常量
const (
// 欧轩互动 -> 普通商户
ApiKey = `2c82c64ceec6ba89ffc9f593c671a12f`
AppId = "wx7b0bcf476552c5e9"
Secret = `f6aabdd40ea25272f4442603a7dc8028`
MchId = `1394404502`
SubMchId = ``
// 欧轩 -> 服务商
//ApiKey = `5x201c8zn43cg675204594cab5423320`
//AppId = `wx662a1633304bfd42`
//Secret = `90df40859d20c95fbb047d48ccbe0a30`
//MchId = `1441266702`
//SubMchId = `1594049151`
WxHost = `https://api.mch.weixin.qq.com`
WxBack = `https://api2.mch.weixin.qq.com`
ClientIp = `123.207.246.51`
)
const (
CODE_SUCCESS = "SUCCESS" // 成功
CODE_FAIL = "FAIL" // 失败
CODE_NOTPAY = "NOTPAY" // 未支付
CODE_CHANGE = "CHANGE" // 退款异常
CODE_REFUNDCLOSE = "REFUNDCLOSE" // 退款关闭
CODE_ERROR = "ERROR" // 业务错误
CODE_INVALID_REQUEST = "INVALID_REQUEST" // 无效请求
CODE_NOAUTH = "NOAUTH" // 异常IP请求不予受理
CODE_NOTENOUGH = "NOTENOUGH" // 余额不足
CODE_ORDERPAID = "ORDERPAID" // 订单已支付
CODE_ORDERCLOSED = "ORDERCLOSED" // 订单已关闭
CODE_SYSTEMERROR = "SYSTEMERROR" // 系统错误
CODE_APPID_NOT_EXIST = "APPID_NOT_EXIST" // APPID不存在
CODE_MCHID_NOT_EXIST = "MCHID_NOT_EXIST" // MCHID不存在
CODE_APPID_MCHID_NOT_MATCH = "APPID_MCHID_NOT_MATCH" // APPID MCHID 不匹配
CODE_LACK_PARAMS = "LACK_PARAMS" // 缺少参数
CODE_OUT_TRADE_NO_USED = "OUT_TRADE_NO_USED" // 商户订单号重复
CODE_SIGNERROR = "SIGNERROR" // 签名错误
CODE_XML_FORMAT_ERROR = "XML_FORMAT_ERROR" // xml格式错误
CODE_REQUIRE_POST_METHOD = "REQUIRE_POST_METHOD" // 请使用post请求方法
CODE_POST_DATA_EMPTY = "POST_DATA_EMPTY" // post数据为空
CODE_NOT_UTF8 = "NOT_UTF8" // 编码错误
CODE_ORDERNOTEXIST = "ORDERNOTEXIST" // 交易订单号不存在
CODE_BIZERR_NEED_RETRY = "BIZERR_NEED_RETRY" // 退款业务流程错误,需要商户触发重试来解决
CODE_TRADE_OVERDUE = "TRADE_OVERDUE" // 订单已经超过退款期限
CODE_USER_ACCOUNT_ABNORMAL = "USER_ACCOUNT_ABNORMAL" // 退款请求失败用户帐号注销
CODE_INVALID_REQ_TOO_MUCH = "INVALID_REQ_TOO_MUCH" // 无效请求过多
CODE_INVALID_TRANSACTIONID = "INVALID_TRANSACTIONID" // 无效transaction_id
CODE_PARAM_ERROR = "PARAM_ERROR" // 参数错误
CODE_FREQUENCY_LIMITED = "FREQUENCY_LIMITED" // 请求频率限制
CODE_TRADE_SUCCESS = "SUCCESS" // 交易成功
CODE_TRADE_REFUND = "REFUND" // 转入退款
CODE_TRADE_NOTPAY = "NOTPAY" // 尚未支付
CODE_TRADE_CLOSED = "CLOSED" // 已关闭
CODE_TRADE_REVOKED = "REVOKED" // 已撤销
CODE_TRADE_USERPAYING = "USERPAYING" // 用户支付中
CODE_TRADE_PAYERROR = "PAYERROR" // 支付失败
CODE_TRANSFER_PROCESSING = "PROCESSING" // 转账处理中
CODE_TRANSFER_NOT_FOUND = "NOT_FOUND" // 账单不见了
)
Loading…
Cancel
Save