Skip to content

Commit

Permalink
增加扫呗支付 (#357)
Browse files Browse the repository at this point in the history
* 扫呗支付
---------
Co-authored-by: reed <[email protected]>
  • Loading branch information
larryclean authored Oct 13, 2023
1 parent a81d7a4 commit a79da7d
Show file tree
Hide file tree
Showing 14 changed files with 653 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func main() {
* #### [拉卡拉支付](https://github.com/go-pay/gopay/blob/main/doc/lakala.md)
* #### [Paypal支付](https://github.com/go-pay/gopay/blob/main/doc/paypal.md)
* #### [Apple支付校验](https://github.com/go-pay/gopay/blob/main/doc/apple.md)
* #### [扫呗支付](https://github.com/go-pay/gopay/blob/main/doc/saobei.md)

---

Expand Down
23 changes: 23 additions & 0 deletions doc/saobei.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## 扫呗支付 API


- 扫呗支付:[官方文档中心](https://help.lcsw.cn/xrmpic/q6imdiojes7iq5y1/qg52lx)



> 具体API使用介绍,请参考`gopay/saobei/client_test.go`

### 支付2.0接口
> 请参考`gopay/saobei/pay_test.go`,
* 小程序支付接口(暂无账号为测试可用性):`client.MiniPay()`
* 付款码支付 `client.BarcodePay()`
* 支付查询 `client.Query()`
* 退款申请 `client.Refund()`
* 退款订单查询 `client.QueryRefund()`

### 资金接口
> 请参考`gopay/saobei/merchant_test.go`,
### CBK企业钱包分账
> 请参考`gopay/saobei/account_test.go`,
3 changes: 3 additions & 0 deletions saobei/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package saobei

//CBK企业钱包分账
14 changes: 14 additions & 0 deletions saobei/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package saobei

const (
// payPath 小程序支付接口
miniPayPath = "/pay/open/minipay"
// barcodePayPath 付款码支付(扫码支付)
barcodePayPath = "/pay/open/barcodepay"
// queryPath 支付查询
queryPath = "/pay/open/query"
// refundPath 退款申请
refundPath = "/pay/open/refund"
// queryRefundPath 退款订单查询
queryRefundPath = "/pay/open/queryrefund"
)
9 changes: 9 additions & 0 deletions saobei/cert/cert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cert

const (
Key = "" // 机构秘钥,扫呗分配
AccessToken = "8ee19b194b504b9c89b88a68b4cdf623" // 支付秘钥,扫呗分配
InstNo = "" // 机构号,扫呗分配
MerchantNo = "858104816000177" // 商户号,扫呗分配
TerminalId = "44350591" // 终端号,扫呗分配
)
95 changes: 95 additions & 0 deletions saobei/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package saobei

import (
"context"
"crypto/md5"
"fmt"
"hash"
"sync"

"github.com/go-pay/gopay/pkg/util"
"github.com/go-pay/gopay/pkg/xlog"

"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/xhttp"
)

type Client struct {
instNo string //商户系统机构号inst_no
key string // 商户系统令牌
merchantNo string // 支付系统:商户号
terminalId string // 支付系统:商户号终端号
accessToken string // 支付系统: 令牌
isProd bool // 是否正式环境
payVer string //版本号 当前201
serviceId string //接口类型,当前类型015
hc *xhttp.Client
mu sync.Mutex
md5Hash hash.Hash
}

// NewClient 初始化扫呗客户端
// instNo string //商户系统机构号inst_no
// key string // 商户系统令牌
// merchantNo string // 支付系统:商户号
// terminalId string // 支付系统:商户号终端号
// accessToken string // 支付系统: 令牌
// isProd:是否是正式环境
func NewClient(instNo, key, merchantNo, terminalId, accessToken string, isProd bool) (*Client, error) {
return &Client{
instNo: instNo,
key: key,
merchantNo: merchantNo,
terminalId: terminalId,
accessToken: accessToken,
isProd: isProd,
hc: xhttp.NewClient(),
md5Hash: md5.New(),
payVer: "201",
serviceId: "015",
}, nil
}

// pubParamsHandle 公共参数处理
func (c *Client) pubParamsHandle(bm gopay.BodyMap) gopay.BodyMap {
if ver := bm.GetString("pay_ver"); ver == util.NULL {
bm.Set("pay_ver", c.payVer)
}
if v := bm.GetString("service_id"); v == util.NULL {
bm.Set("service_id", c.serviceId)
}
if v := bm.GetString("merchant_no"); v == util.NULL {
bm.Set("merchant_no", c.merchantNo)
}
if v := bm.GetString("terminal_id"); v == util.NULL {
bm.Set("terminal_id", c.terminalId)
}
sign := c.getRsaSign(bm)

bm.Set("key_sign", sign)

return bm
}

// doPost 发起请求
func (c *Client) doPost(ctx context.Context, path string, bm gopay.BodyMap) (bs []byte, err error) {
param := c.pubParamsHandle(bm)
if err != nil {
return nil, err
}

xlog.Debugf("saobeiParam:%+v", param.JsonBody())

url := baseUrl
if !c.isProd {
url = sandboxBaseUrl
}
res, bs, err := c.hc.Req(xhttp.TypeJSON).Post(url + path).SendBodyMap(param).EndBytes(ctx)
if err != nil {
return nil, err
}
if res.StatusCode != 200 {
return nil, fmt.Errorf("HTTP Request Error, StatusCode = %d", res.StatusCode)
}
return bs, nil
}
33 changes: 33 additions & 0 deletions saobei/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package saobei

import (
"context"
"os"
"testing"

"github.com/go-pay/gopay/pkg/xlog"
"github.com/go-pay/gopay/saobei/cert"
)

var (
ctx = context.Background()
client *Client
err error
)

func TestMain(m *testing.M) {
// 初始化通联客户端
// instNo string //商户系统机构号inst_no
// key string // 商户系统令牌
// merchantNo string // 支付系统:商户号
// terminalId string // 支付系统:商户号终端号
// accessToken string // 支付系统: 令牌
// isProd:是否是正式环境
client, err = NewClient(cert.InstNo, cert.Key, cert.MerchantNo, cert.TerminalId, cert.AccessToken, false)
if err != nil {
xlog.Error(err)
return
}

os.Exit(m.Run())
}
41 changes: 41 additions & 0 deletions saobei/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package saobei

const (
baseUrl = "https://pay.lcsw.cn/lcsw"
sandboxBaseUrl = "http://test2.lcsw.cn:8117/lcsw"

//PayTypeWX 支付方式:微信
PayTypeWX = "010"
//PayTypeAli 支付方式:支付宝
PayTypeAli = "020"
//PayTypeQQ 支付方式:QQ钱包
PayTypeQQ = "060"
//PayTypeYi 支付方式:翼支付
PayTypeYi = "100"
//PayTypeYL 支付方式:银联二维码
PayTypeYL = "110"

//ResultCodeSuccess 业务结果:01 成功
ResultCodeSuccess = "01"
//ResultCodeFail 业务结果:02 失败
ResultCodeFail = "02"
//ResultCodePaying 业务结果:03 支付中
ResultCodePaying = "03"

//TradeStatusSuccess 交易订单状态:支付成功
TradeStatusSuccess = "SUCCESS"
//TradeStatusRefund 交易订单状态:转入退款
TradeStatusRefund = "REFUND"
//TradeStatusNotPay 交易订单状态:未支付
TradeStatusNotPay = "NOTPAY"
//TradeStatusClosed 交易订单状态:已关闭
TradeStatusClosed = "CLOSED"
//TradeStatusUserPaying 交易订单状态:用户支付中
TradeStatusUserPaying = "USERPAYING"
//TradeStatusRevoked 交易订单状态:已撤销
TradeStatusRevoked = "REVOKED"
//TradeStatusNoPay 交易订单状态:未支付支付超时
TradeStatusNoPay = "NOPAY"
//TradeStatusPayError 交易订单状态:支付失败
TradeStatusPayError = "PAYERROR"
)
32 changes: 32 additions & 0 deletions saobei/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package saobei

import (
"fmt"
)

// BizErr 用于判断通联的业务逻辑是否有错误
type BizErr struct {
Code string `json:"code"`
Msg string `json:"msg"`
}

// bizErrCheck 检查返回码是否为SUCCESS 否则返回一个BizErr
func bizErrCheck(resp RspBase) error {
if resp.ReturnCode != "01" {
return &BizErr{
Code: resp.ReturnCode,
Msg: resp.ReturnMsg,
}
}
//if resp.ResultCode != "01" {
// return &BizErr{
// Code: resp.ResultCode,
// Msg: resp.ReturnMsg,
// }
//}
return nil
}

func (e *BizErr) Error() string {
return fmt.Sprintf(`[%s]%s`, e.Code, e.Msg)
}
1 change: 1 addition & 0 deletions saobei/merchant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package saobei
Loading

0 comments on commit a79da7d

Please sign in to comment.