黄梓健
5 years ago
29 changed files with 660 additions and 503 deletions
-
1controllers/client/bully_screen.go
-
16controllers/client/live.go
-
8controllers/client/login.go
-
2controllers/client/order_entry.go
-
25controllers/client/shake_red_envelope.go
-
20controllers/common/wechat_oauth.go
-
44go.mod
-
105go.sum
-
2models/auction_history.go
-
2models/bahe_team_member.go
-
14models/base.go
-
7models/bully_screen_history.go
-
2models/customer_order.go
-
13models/live_red_pack.go
-
4models/new_auction_activity.go
-
7models/reward_history.go
-
8models/shake_red_envelope_record.go
-
29models/user_order.go
-
2models/user_prize.go
-
12models/user_red_pack.go
-
17models/user_refund.go
-
46services/pay/client.go
-
84services/pay/const.go
-
285services/pay/order.go
-
12services/pay/pay_test.go
-
179services/pay/refund.go
-
187services/pay/transfer.go
-
13test/pay_test.go
-
1utils/code/code.go
@ -0,0 +1,84 @@ |
|||
package pay_service |
|||
|
|||
import ( |
|||
"fmt" |
|||
"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 ( |
|||
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" // 支付失败
|
|||
) |
|||
|
|||
type CommonReturn struct { |
|||
ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"` |
|||
ReturnMsg string `xml:"return_msg,omitempty" json:"return_msg,omitempty"` |
|||
} |
|||
|
|||
type CommonResult struct { |
|||
ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"` |
|||
ResultMsg string `xml:"result_msg,omitempty" json:"result_msg,omitempty"` |
|||
ErrCode string `xml:"err_code,omitempty" json:"err_code,omitempty"` |
|||
ErrCodeDes string `xml:"err_code_des,omitempty" json:"err_code_des,omitempty"` |
|||
} |
@ -0,0 +1,12 @@ |
|||
package pay_service |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
) |
|||
|
|||
func TestTransfer(t *testing.T) { |
|||
res, err := Transfer("欧轩互动-转账测试", "127.0.0.1", "o9XM41s_NN8Y0QK6_MbM-aYMV3TE", 1) |
|||
fmt.Println(err) |
|||
fmt.Printf("%+v\n", res) |
|||
} |
@ -1,148 +1,129 @@ |
|||
package pay_service |
|||
|
|||
import ( |
|||
"encoding/xml" |
|||
"fmt" |
|||
"github.com/iGoogle-ink/gopay/v2" |
|||
"github.com/iGoogle-ink/gopay/v2/wechat" |
|||
"github.com/ouxuanserver/osmanthuswine/src/core" |
|||
"hudongzhuanjia/libs/wx" |
|||
"hudongzhuanjia/logger" |
|||
"github.com/chanxuehong/wechat/mch/mmpaymkttransfers" |
|||
"github.com/chanxuehong/wechat/mch/mmpaymkttransfers/promotion" |
|||
"hudongzhuanjia/models" |
|||
"hudongzhuanjia/utils" |
|||
"time" |
|||
) |
|||
|
|||
func TransferExtend(bm gopay.BodyMap) (*wechat.TransfersResponse, error) { |
|||
err := bm.CheckEmptyError("nonce_str", "partner_trade_no", "openid", "check_name", "amount", "desc", "spbill_create_ip") |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
bs, err := ClientExtend(bm, wx.TransfersURL) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
wxRsp := new(wechat.TransfersResponse) |
|||
if err = xml.Unmarshal(bs, wxRsp); err != nil { |
|||
return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err) |
|||
} |
|||
return wxRsp, nil |
|||
// 企业向微信用户个人付款(不支持沙箱环境)
|
|||
type TransferResponse struct { |
|||
DeviceInfo string `xml:"device_info,omitempty" json:"device_info,omitempty"` |
|||
NonceStr string `xml:"nonce_str,omitempty" json:"nonce_str,omitempty"` |
|||
PartnerTradeNo string `xml:"partner_trade_no,omitempty" json:"partner_trade_no,omitempty"` |
|||
PaymentNo string `xml:"payment_no,omitempty" json:"payment_no,omitempty"` |
|||
PaymentTime string `xml:"payment_time,omitempty" json:"payment_time,omitempty"` |
|||
} |
|||
|
|||
// 企业向微信用户个人付款(不支持沙箱环境)
|
|||
func Transfer(desc, ip, openId string, amount int) (*wechat.TransfersResponse, error) { |
|||
func Transfer(desc, ip, openId string, amount int) (*TransferResponse, error) { |
|||
|
|||
nonceStr := gopay.GetRandomString(32) |
|||
partnerTradeNo := gopay.GetRandomString(32) |
|||
nonceStr := utils.RandomStr(32) |
|||
partnerTradeNo := utils.RandomStr(32) |
|||
// 初始化参数结构体
|
|||
body := make(gopay.BodyMap) |
|||
body.Set("nonce_str", nonceStr) |
|||
body.Set("partner_trade_no", partnerTradeNo) |
|||
body.Set("openid", openId) |
|||
body.Set("check_name", "NO_CHECK") // NO_CHECK:不校验真实姓名 , FORCE_CHECK:强校验真实姓名
|
|||
body.Set("amount", amount) // 企业付款金额,单位为分
|
|||
body.Set("desc", desc) // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
|
|||
body.Set("spbill_create_ip", ip) |
|||
body.Set("mchid", wx.Mchid) |
|||
body.Set("mch_appid", wx.Appid) |
|||
|
|||
res, err := TransferExtend(body) |
|||
body := make(map[string]string) |
|||
body["nonce_str"] = nonceStr |
|||
body["partner_trade_no"] = partnerTradeNo |
|||
body["openid"] = openId |
|||
body["check_name"] = "NO_CHECK" // NO_CHECK:不校验真实姓名 , FORCE_CHECK:强校验真实姓名
|
|||
body["amount"] = fmt.Sprintf("%d", amount) // 企业付款金额,单位为分
|
|||
body["desc"] = desc // 企业付款备注,必填。注意:备注中的敏感词会被转成字符*
|
|||
body["spbill_create_ip"] = ip |
|||
body["mchid"] = Mchid |
|||
body["mch_appid"] = Appid |
|||
|
|||
client, err := Client() |
|||
m, err := promotion.Transfers(client, body) |
|||
if err != nil { |
|||
fmt.Println("Error:", err) |
|||
return nil, err |
|||
} |
|||
fmt.Println("wxRsp:", *res) |
|||
// 保存到user_transfer
|
|||
res := &TransferResponse{ |
|||
DeviceInfo: m["device_info"], |
|||
NonceStr: m["nonce_str"], |
|||
PartnerTradeNo: m["partner_trade_no"], |
|||
PaymentNo: m["payment_no"], |
|||
PaymentTime: m["payment_time"], |
|||
} |
|||
return res, nil |
|||
} |
|||
|
|||
func QueryTransfer(partnerTradeNo string) { |
|||
body := make(gopay.BodyMap) |
|||
body.Set("nonce_str", gopay.GetRandomString(32)) |
|||
body.Set("partner_trade_no", partnerTradeNo) |
|||
// todo: 查询, 遇到查询失败,需要原订单号重新请求
|
|||
type RedPackResult struct { |
|||
MchBillno string `xml:"mch_billno,omitempty" json:"mch_billno,omitempty"` |
|||
ReOpenid string `xml:"re_openid,omitempty" json:"re_openid,omitempty"` |
|||
TotalAmount int `xml:"total_amount,omitempty" json:"total_amount,omitempty"` |
|||
SendListid string `xml:"send_listid,omitempty" json:"send_listid,omitempty"` |
|||
} |
|||
|
|||
// 发送红包
|
|||
func SendRedPack(sendName, openId, wishing, ip, actName, remark string, totalAmount, totalNum, scene int) (*wx.RedPackResult, error) { |
|||
mchBillNo := gopay.GetRandomString(28) |
|||
|
|||
body := make(gopay.BodyMap) |
|||
body.Set("nonce_str", gopay.GetRandomString(32)) |
|||
body.Set("mch_billno", mchBillNo) |
|||
body.Set("send_name", sendName) |
|||
body.Set("re_openid", openId) |
|||
body.Set("total_amount", totalAmount) |
|||
body.Set("total_num", totalNum) |
|||
body.Set("wishing", wishing) |
|||
body.Set("client_ip", ip) |
|||
body.Set("act_name", actName) |
|||
body.Set("remark", remark) |
|||
body.Set("scene_id", fmt.Sprintf("PRODUCT_%d", scene)) |
|||
body.Set("wxappid", wx.Appid) |
|||
body.Set("mch_id", wx.Mchid) |
|||
|
|||
bs, err := ClientExtend(body, wx.SendRedPackURL) |
|||
func SendRedPack(sendName, openId, wishing, ip, actName, remark string, totalAmount, totalNum, scene int) (*RedPackResult, error) { |
|||
mchBillNo := utils.RandomStr(28) |
|||
nonceStr := utils.RandomStr(32) |
|||
|
|||
body := make(map[string]string, 0) |
|||
body["nonce_str"] = nonceStr |
|||
body["mch_billno"] = mchBillNo |
|||
body["send_name"] = sendName |
|||
body["re_openid"] = openId |
|||
body["total_amount"] = fmt.Sprintf("%d", totalAmount) |
|||
body["total_num"] = fmt.Sprintf("%d", totalNum) |
|||
body["wishing"] = wishing |
|||
body["client_ip"] = ip |
|||
body["act_name"] = actName |
|||
body["remark"] = remark |
|||
body["scene_id"] = fmt.Sprintf("PRODUCT_%d", scene) |
|||
body["ppid"] = Appid |
|||
body["mch_id"] = Mchid |
|||
|
|||
client, err := Client() |
|||
m, err := mmpaymkttransfers.SendRedPack(client, body) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
res := new(wx.RedPackResult) |
|||
if err = xml.Unmarshal(bs, res); err != nil { |
|||
logger.Sugar.Errorf("xml.Unmarshal(%s): %s", string(bs), err) |
|||
return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err) |
|||
} |
|||
|
|||
if res.ReturnCode != wx.CODE_SUCCESS { |
|||
err = fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg) |
|||
logger.Sugar.Error(err) |
|||
return nil, err |
|||
res := &RedPackResult{ |
|||
MchBillno: m["mch_billno"], |
|||
ReOpenid: m["re_openid"], |
|||
TotalAmount: totalAmount, |
|||
SendListid: m["send_listid"], |
|||
} |
|||
|
|||
userRedPack := new(models.UserRedPack) |
|||
userRedPack.ErrCode = res.ErrCode |
|||
userRedPack.ErrCodeDes = res.ErrCodeDes |
|||
userRedPack.MchBillno = mchBillNo |
|||
userRedPack.ReOpenid = openId |
|||
userRedPack.SceneId = scene |
|||
userRedPack.SendListid = res.SendListid |
|||
userRedPack.TotalAmount = totalAmount |
|||
userRedPack.TotalNum = totalNum |
|||
userRedPack.ResultCode = res.ResultCode |
|||
userRedPack.IsDelete = false |
|||
userRedPack.UpdatedAt = time.Now() |
|||
userRedPack.CreatedAt = time.Now() |
|||
if _, err := core.GetXormAuto().InsertOne(userRedPack); err != nil { |
|||
logger.Sugar.Errorf("insert into user red pack error: %s", err) |
|||
_, err = userRedPack.AddRedPack() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
return res, nil |
|||
|
|||
} |
|||
|
|||
// todo: 小心谨慎查询
|
|||
func QueryRedPack(mchBillno string) (*wx.QueryRedPackResult, error) { |
|||
body := make(gopay.BodyMap) |
|||
body.Set("nonce_str", gopay.GetRandomString(32)) |
|||
body.Set("mch_billno", mchBillno) |
|||
body.Set("bill_type", "MCHT") |
|||
body.Set("appid", wx.Appid) |
|||
body.Set("mch_id", wx.Mchid) |
|||
bs, err := ClientExtend(body, wx.QueryRedPackURL) |
|||
if err != nil { |
|||
logger.Sugar.Errorf("client extend request wx error: %s", err) |
|||
return nil, err |
|||
} |
|||
res := new(wx.QueryRedPackResult) |
|||
if err = xml.Unmarshal(bs, res); err != nil { |
|||
logger.Sugar.Errorf("xml.Unmarshal(%s):%s", string(bs), err) |
|||
return nil, fmt.Errorf("xml.Unmarshal(%s):%s", string(bs), err) |
|||
} |
|||
if res.ReturnCode != wx.CODE_SUCCESS { |
|||
err = fmt.Errorf("network error, retrun_code: %v and return_msg: %v", res.ReturnCode, res.ReturnMsg) |
|||
logger.Sugar.Error(err) |
|||
return nil, err |
|||
} |
|||
|
|||
return res, nil |
|||
type QueryRedPackResult struct { |
|||
CommonReturn |
|||
CommonResult |
|||
MchBillno string `xml:"mch_billno,omitempty" json:"mch_billno,omitempty"` |
|||
Mchid string `xml:"mchid,omitempty" json:"mchid,omitempty"` |
|||
DetailId string `xml:"detail_id,omitempty" json:"detail_id,omitempty"` |
|||
Status string `xml:"status,omitempty" json:"status,omitempty"` |
|||
SendType string `xml:"send_type,omitempty" json:"send_type,omitempty"` |
|||
HbType string `xml:"hb_type,omitempty" json:"hb_type,omitempty"` |
|||
TotalNum int `xml:"total_num,omitempty" json:"total_num,omitempty"` |
|||
TotalAmount int `xml:"total_amount,omitempty" json:"total_amount,omitempty"` |
|||
Reason string `xml:"reason,omitempty" json:"reason,omitempty"` |
|||
SendTime string `xml:"send_time,omitempty" json:"send_time,omitempty"` |
|||
RefundTime string `xml:"refund_time,omitempty" json:"refund_time,omitempty"` |
|||
RefundAmount int `xml:"refund_amount,omitempty" json:"refund_amount,omitempty"` |
|||
Wishing string `xml:"wishing,omitempty" json:"wishing,omitempty"` |
|||
Remark string `xml:"remark,omitempty" json:"remark,omitempty"` |
|||
ActName string `xml:"act_name,omitempty" json:"act_name,omitempty"` |
|||
} |
@ -0,0 +1,13 @@ |
|||
package test |
|||
|
|||
import ( |
|||
"fmt" |
|||
pay_service "hudongzhuanjia/services/pay" |
|||
"testing" |
|||
) |
|||
|
|||
func TestTransfer(t *testing.T) { |
|||
res, err := pay_service.Transfer("欧轩互动-转账测试", "127.0.0.1", "o9XM41s_NN8Y0QK6_MbM-aYMV3TE", 30) |
|||
fmt.Println(err) |
|||
fmt.Printf("%+v\n", res) |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue