Commit 47990473 authored by wangp's avatar wangp

拉卡拉统一支付微信回调

parent fbce7a23
package pay
import (
"github.com/gin-gonic/gin"
"system_pay/controller/base"
"system_pay/models"
"system_pay/repository/pay"
)
// 卡拉卡统一支付回调
type NoticeController struct {
}
// WxNotice 拉卡拉统一支付微信回调
// @Summary 拉卡拉统一支付微信回调
// @Description 拉卡拉统一支付微信回调
// @Tags 拉卡拉统一支付回调
// @Accept application/json
// @Produce application/json
// @Param language header string ture "语言类型 zh-CN简体中文 en-US英文 ja 日文 默认中文"
// @Success 200
// @router /api/v1/pay/wx_notice [post]
func (l *PayController) WxNotice(c *gin.Context) {
ph := new(models.WxNoticeInput)
err := c.ShouldBind(ph)
if err != nil {
response := new(base.ResponseDataWxNotice)
response.Code = "FAIL"
response.Message = "执行失败"
base.ResponseWxNotice(c, response)
return
}
// 绑定
response, err := pay.WxNotice(ph)
base.ResponseWxNotice(c, response)
}
......@@ -73,3 +73,15 @@ func ResponseErrorMsg(c *gin.Context, msg string) {
Data: nil,
})
}
// ResponseDataWxNotice 微信回调后 处理完逻辑返回给微信的信息
type ResponseDataWxNotice struct {
Code string `json:"code"` //SUCCESS/FAIL
Message string `json:"message"` //执行成功/错误原因
}
func ResponseWxNotice(c *gin.Context, data *ResponseDataWxNotice) {
c.JSON(http.StatusOK, &ResponseDataWxNotice{
Code: data.Code,
Message: data.Message,
})
}
\ No newline at end of file
package models
// WxNoticeInput 微信回调输入参数
type WxNoticeInput struct {
ChannelId uint8 `json:"channel_id" description:"平台类型 1: saas 2: shop 3: shop mobile 4: 收银台"`
MerchantNo string `json:"merchant_no" description:"平台信息"`
OrderCreateTime string `json:"order_create_time" description:"商品描述"`
OrderEfficientTime string `json:"order_efficient_time" description:"商品详情"`
OrderInfo string `json:"order_info" description:"附加信息"`
OrderStatus float64 `json:"order_status" description:"商品金额,个位为分"`
OutOrderNo string `json:"out_order_no" description:"客户端回调的url"`
PayOrderNo int `json:"pay_order_no" description:"1: 微信,2: 支付宝, 3: 拉卡拉 4: 收钱吧"`
TermNo uint8 `json:"term_no" description:"1: 微信 Native 2:微信小程序 3:微信内支付 4:h5 跳微信 5:支付宝(web)-扫码或登录支付宝账户 6:alipay(mobile) 7:alipay(app) 9: B2C 10:bk支付宝web 11:bk 支付宝手机"`
TotalAmount string `json:"total_amount" description:"此参数 支付类型是 JS API 的时候 必传"`
TransMerchantNo string `json:"trans_merchant_no" description:"WAP网站URL地址, 支付方式为微信MWEB时 必传"`
TransTermNo string `json:"trans_term_no" description:"WAP网站名称, 支付方式为微信MWEB时 必传"`
}
// CallbackResponse is 回调给业务方的信息
type CallbackResponse struct {
OutTradeNo string `json:"out_trade_no"` // 订单号
ReturnMsg string `json:"return_msg"` // 是否成功
AttachInfo string `json:"attach_info"` // 附加信息
TransactionID string `json:"transaction_id"` // 微信支付订单号
TradeNo string `json:"trade_no"` // 支付宝交易流水号
}
package pay
import (
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/astaxie/beego"
)
var (
callBackNumMap = map[int]int64{
1: 1,
2: 2,
3: 4,
4: 8,
5: 16,
6: 32,
7: 64,
8: 128,
9: 256,
10: 512,
11: 1024,
12: 2048,
}
)
func callBackBusinessService(outTradeNo, url string, data interface{}) {
body, _ := json.Marshal(data)
// callBackResponseData is 业务方回调过来的数据
type callBackResponseData struct {
Code int
Message string
Data interface{}
}
number := 1
for {
client := &http.Client{}
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(string(body)))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
beego.Error("网络请求错误")
second := callBackNumMap[number]
timeSleep := float64(time.Second) * float64(second)
number++
beego.Info("当前等待: ", number, "订单号: ", outTradeNo)
time.Sleep(time.Duration(int64(timeSleep)))
continue
}
bodyResp, err := ioutil.ReadAll(resp.Body)
beego.Info("bodyResp: ", string(bodyResp))
if err != nil {
beego.Error("从 业务方 response sbody中取数据失败")
second := callBackNumMap[number]
timeSleep := float64(time.Second) * float64(second)
number++
beego.Info("当前等待: ", number, "订单号: ", outTradeNo)
time.Sleep(time.Duration(int64(timeSleep)))
continue
}
resp.Body.Close()
// 解析业务方数据
businessResp := new(callBackResponseData)
if err := json.Unmarshal(bodyResp, businessResp); err != nil {
beego.Error("解析业务方返回的数据失败", string(bodyResp))
return
}
if businessResp.Code == 0 || businessResp.Message == "SUCCESS" {
beego.Info("回调业务方成功: ", "订单号: ", outTradeNo, "回调了%v次", number)
return
}
if number >= 12 {
beego.Info("当前等待: ", number, "订单号: ", outTradeNo, "结束回调")
return
}
second := callBackNumMap[number]
timeSleep := float64(time.Second) * float64(second)
beego.Info("当前等待: ", number, "订单号: ", outTradeNo)
number++
time.Sleep(time.Duration(int64(timeSleep)))
}
}
package pay
import (
"encoding/json"
"fmt"
"strconv"
"system_pay/controller/base"
"system_pay/models"
"system_pay/mysql"
)
// 拉卡拉微信支付回调 - AliPayNotice
func WxNotice(input *models.WxNoticeInput) (*base.ResponseDataWxNotice, error) {
fmt.Println("接口输入参数")
fmt.Println(input)
response := new(base.ResponseDataWxNotice)
db, err := mysql.NewShopConn()
if err != nil {
response.Code = "FAIL"
response.Message = "参数格式校验错误"
return response, err
}
fmt.Println("111")
//1.订单合法check
var billID int64
var attach, url string
err = db.QueryRow("select ifnull(id, 0), attach, notify_pay_url from pay_bill where payment_order_code = ?",
input.OutOrderNo).Scan(&billID, &attach, &url)
if err != nil || billID == 0 || billID == 2 {
response.Code = "FAIL"
response.Message = "db operation fail"
return response, err
}
fmt.Println("222")
//2.存入 notice_request_body
err = InsertPayBillDetailNoticeRequestBody(billID, input)
if err != nil {
//beego.Error("微信回调, 根据订单id 插入回调Request参数 失败: ", err)
response.Code = "FAIL"
response.Message = "db operation fail"
InsertPayBillDetailNoticeResponseBody(billID, response)
return response, err
}
fmt.Println("333")
//3.存入 notice_response_body
//err = InsertPayBillDetailNoticeResponseBody(billID, response)
//if err != nil {
// beego.Error("微信回调, 根据订单id 插入回调Response参数 失败: ", err)
// response.ReturnCode = "FAIL"
// response.ReturnMsg = "db operation fail"
// return err
//}
//beego.Info("回调成功 订单成功")
//type CallbackResponse struct {
// OutTradeNo string `json:"out_trade_no"` // 订单号
// ReturnMsg string `json:"return_msg"` // 是否成功
// AttachInfo string `json:"attach_info"` // 附加信息
// TransactionID string `json:"transaction_id"` // 微信支付订单号
// TradeNo string `json:"trade_no"` // 支付宝交易流水号
//}
if url != "" {
//4.回调业务方「回调函数」
callbackResponse := new(models.CallbackResponse)
callbackResponse.ReturnMsg = "SUCCESS"
//callbackResponse.OutTradeNo = input.OutTradeNo
//callbackResponse.TransactionID = input.TransactionId
callbackResponse.OutTradeNo = strconv.Itoa(input.PayOrderNo) //交易凭据单号 todo
callbackResponse.TransactionID = strconv.Itoa(input.PayOrderNo) //交易凭据单号 todo
attachMap := make(map[string]interface{}, 0)
_ = json.Unmarshal([]byte(attach), &attachMap)
if attachMap["store_sn"].(string) == "" {
callbackResponse.AttachInfo = attachMap["old_attach"].(string)
} else {
callbackResponse.AttachInfo = attach //商户订单号(谛宝多多)
}
go callBackBusinessService(input.OutOrderNo, url, callbackResponse)
fmt.Println("444")
}
response.Code = "SUCCESS"
response.Message = "执行成功"
InsertPayBillDetailNoticeResponseBody(billID, response)
return response, nil
}
// InsertPayBillDetailNoticeRequestBody is 插入支付订单详情表中的 下单参数字段 notice_request_body
func InsertPayBillDetailNoticeRequestBody(billID int64, noticeRequestBody interface{}) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
body, err := json.Marshal(noticeRequestBody)
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill_detail set notice_request_body = ? where pay_bill_id = ?`
result, err := db.Exec(insertPayBillDetailSQL, string(body), billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
// InsertPayBillDetailNoticeResponseBody is 插入支付订单详情表中的 下单参数字段 notice_response_body
func InsertPayBillDetailNoticeResponseBody(billID int64, noticeResponseBody interface{}) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
body, err := json.Marshal(noticeResponseBody)
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill_detail set notice_response_body = ? where pay_bill_id = ?`
result, err := db.Exec(insertPayBillDetailSQL, string(body), billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
......@@ -11,10 +11,12 @@ import (
"encoding/pem"
"errors"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/httplib"
rand2 "math/rand"
"strings"
"system_pay/models"
"system_pay/mysql"
"time"
)
......@@ -31,11 +33,11 @@ func UnifiedOrder(input *models.PlaceAnOrderParamInput) (interface{}, error) {
//}
//rtn := make(map[string]string)
fmt.Println("接口输入参数")
fmt.Println("拉卡拉支付接口输入参数")
fmt.Println(input)
data := make(map[string]interface{})
data["req_time"] = "20220714160009"
data["req_time"] = "20230626100000"
data["version"] = "3.0"
data["out_org_code"] = "OP00000003"
......@@ -57,22 +59,29 @@ func UnifiedOrder(input *models.PlaceAnOrderParamInput) (interface{}, error) {
// "extend_info": "自动化测试",
// "callback_url": ""
input.NoticeURL = "https://test.pet-dbc.cn/uni/api/repayment/PayCallBack"
//input.NoticeURL = "https://test.pet-dbc.cn/uni/api/repayment/PayCallBack"
//input.NoticeURL = "https://test.pet-dbc.cn/mobile/notifywx.php"
input.ReturnURL = "https://test.pet-dbc.cn"
// 构造回调url
input.NoticeURL = GetNoticeURL(input.SourceCode)
// 传递给支付渠道的
//p.ServeNoticeUrl = noticeURLx
data2 := make(map[string]interface{})
//data2["out_trade_no"] = "FD660E1FAA3A4470933CDEDAE1EC1DUU"
data2["out_trade_no"] = RandomString(32)
data2["merchant_no"] = "822290070111135"
//data2["merchant_no"] = "822290070111135"
data2["merchant_no"] = "8222900701107M5"
data2["term_no"] = "29034705"
//data2["merchant_no"] = "8222900581201QB"
//data2["term_no"] = "D0027598"
data2["auth_code"] = "135178236713755038"
data2["total_amount"] = "123"
data2["total_amount"] = "1"
//data2["out_order_no"] = "08F4542EEC6A4497BC419161747A92UU"
data2["out_order_no"] = RandomString(32)
data2["order_efficient_time"] = "20230620130000" //订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+2天
data2["order_efficient_time"] = "20230630235959" //订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+2天
data2["notify_url"] = input.NoticeURL //订单支付成功后商户接收订单通知的地址 http://xxx.xxx.com
data2["callback_url"] = input.ReturnURL //客户端下单完成支付后返回的商户网页跳转地址
......@@ -503,3 +512,181 @@ func RandomString(n int) string {
}
return string(result)
}
// GetNoticeURL is 获取回调地址
func GetNoticeURL(sourceCode uint8) string {
domainName := beego.AppConfig.String("DomainName")
// <= 5 是微信
if sourceCode < 5 {
return domainName + "/v1/pay/wx_notice"
}
// > 5 是支付宝
return domainName + "/v1/pay/alipay_notice"
//
//if isServe == 0 {
// // payType 1: 原生 2: paymax
// if payType == 1 {
//
// // <= 5 是微信 > 5 是支付宝
// if sourceCode < 5 {
// return domainName + "/v1/notice/wx"
// }
//
// return domainName + "/v1/notice/ali"
// }
//
// return domainName + "/v1/notice/paymax"
//}
//
//// <= 5 是微信 > 5 是支付宝
//if sourceCode < 5 {
// return domainName + "/v1/notice/serve_wx"
//}
//
//return domainName + "/v1/notice/serve_ali"
}
// BillPayStateSuccess is 微信回调后 把订单状态 置为结算成功
func BillPayStateSuccess(billID int64) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill set result_code = 1 where id = ?`
result, err := db.Exec(insertPayBillDetailSQL, billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
// BillPayStateFail is 微信回调后 把订单状态 置为结算失败
func BillPayStateFail(billID int64) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill set result_code = 2 where id = ?`
result, err := db.Exec(insertPayBillDetailSQL, billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
//InsertPayBill is 插入 支付订单表中
func InsertPayBill(p *models.PlaceAnOrderParamInput, orderID string) (int64, error) {
db, err := mysql.NewShopConn()
if err != nil {
return 0, err
}
var billID int64
insertSQL := `insert pay_bill set platform_type = ?, platform_info = ?,
source_code = ?, payment_order_code = ?, paymoney = ?*1000, commodity_describe = ?,
commodity_detail = ?, attach = ?, notify_pay_url = ?, pay_type = ?, is_serve = ?`
result, err := db.Exec(insertSQL, p.PlatformType, p.PlatformInfo, p.SourceCode,
orderID, p.GoodsPrice, p.GoodsDes, p.GoodsDetail, p.AttachInfo, p.NoticeURL, p.PayType, p.IsServe)
if err != nil {
return billID, err
}
billID, err = result.LastInsertId()
if err != nil {
return billID, err
}
return billID, nil
}
// InsertPayBillDetailRequestBody is 插入支付订单详情表中的 下单参数字段 request_body
func InsertPayBillDetailRequestBody(billID int64, requestBody interface{}) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
body, err := json.Marshal(requestBody)
if err != nil {
return err
}
insertPayBillDetailSQL := `insert pay_bill_detail set pay_bill_id = ?, request_body = ?`
result, err := db.Exec(insertPayBillDetailSQL, billID, string(body))
if err != nil {
return err
}
_, err = result.LastInsertId()
if err != nil {
return err
}
return nil
}
// InsertPayBillDetailResponseBody is 插入支付订单详情表中的 下单参数字段 response_body
func InsertPayBillDetailResponseBody(billID int64, responseBody interface{}) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
body, err := json.Marshal(responseBody)
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill_detail set response_body = ? where pay_bill_id = ?`
result, err := db.Exec(insertPayBillDetailSQL, string(body), billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
func InsertPayBillDetailResponseBodyString(billID int64, responseBody string) error {
db, err := mysql.NewShopConn()
if err != nil {
return err
}
insertPayBillDetailSQL := `update pay_bill_detail set response_body = ? where pay_bill_id = ?`
result, err := db.Exec(insertPayBillDetailSQL, responseBody, billID)
if err != nil {
return err
}
_, err = result.RowsAffected()
if err != nil {
return err
}
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment