583 lines
17 KiB
Markdown
583 lines
17 KiB
Markdown
# 拉卡拉SDK
|
||
|
||
这是一个通用的拉卡拉SDK,提供了分账、交易、账户等功能的API接口封装,方便开发者快速集成拉卡拉支付服务。
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
lklsdk/
|
||
├── client.go # 核心客户端
|
||
├── split_ledger.go # 分账基本功能
|
||
├── split_ledger_more.go # 分账扩展功能
|
||
├── trade.go # 交易相关功能
|
||
├── account.go # 账户相关功能
|
||
├── merge_pre.go # 主扫合单交易功能
|
||
├── sdk.go # SDK主入口
|
||
├── merchant.go # 商户相关功能
|
||
└── uploadFile.go # 文件上传相关功能
|
||
```
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
# 将SDK引入到您的项目中
|
||
go get -u github.com/black1552/lkl_sdk
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 初始化SDK
|
||
|
||
```go
|
||
import (
|
||
"github.com/black1552/lkl_sdk/lklsdk"
|
||
"github.com/black1552/lkl_sdk/model"
|
||
"github.com/black1552/lkl_sdk/consts"
|
||
"github.com/gogf/gf/v2/os/gctx"
|
||
)
|
||
|
||
// 创建配置JSON字符串
|
||
cfgJson := `{
|
||
"public_key": "your_public_key", // 公钥字符串
|
||
"private_key": "your_private_key", // 私钥字符串
|
||
"app_id": "your_app_id", // lakala应用ID
|
||
"serial_no": "your_serial_no", // 序列号
|
||
"sub_app_id": "your_sub_app_id", // 子应用ID 微信AppId
|
||
"version": "3.0", // lakala版本号
|
||
"account_type": "WECHAT", // 账户类型
|
||
"trans_type": "71", // 交易类型
|
||
"notify_url": "your_notify_url" // 回调地址
|
||
}`
|
||
|
||
// 初始化SDK(使用泛型指定响应类型)
|
||
sdk := lklsdk.NewSDK[model.ResponseType](gctx.New(), cfgJson)
|
||
```
|
||
|
||
## 功能模块
|
||
|
||
### 1. 主扫合单交易
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.MergePreorderResponse](gctx.New(), cfgJson)
|
||
|
||
// 准备拆单信息
|
||
outSplitInfo := []*model.OutSplitInfo{
|
||
{
|
||
OutSubTradeNo: "子交易流水号1",
|
||
MerchantNo: config.MerchantNo,
|
||
TermNo: config.TermNo,
|
||
Amount: "100", // 1元
|
||
},
|
||
{
|
||
OutSubTradeNo: "子交易流水号2",
|
||
MerchantNo: config.MerchantNo,
|
||
TermNo: config.TermNo,
|
||
Amount: "200", // 2元
|
||
},
|
||
}
|
||
|
||
// 构建位置信息
|
||
locationInfo := &model.LocationInfo{
|
||
RequestIp: "127.0.0.1",
|
||
}
|
||
|
||
// 构建请求参数
|
||
mergePreorderReq := &model.MergePreorderReqData{
|
||
MerchantNo: config.MerchantNo,
|
||
TermNo: config.TermNo,
|
||
OutTradeNo: "商户交易流水号",
|
||
OutSplitInfo: outSplitInfo,
|
||
AccountType: "WECHAT",
|
||
TransType: "71",
|
||
TotalAmount: "300", // 3元
|
||
LocationInfo: locationInfo,
|
||
Subject: "测试订单",
|
||
NotifyUrl: "https://your-notify-url.com",
|
||
}
|
||
|
||
// 调用接口
|
||
mergePreorderResp, err := sdk.MergePreOrder(mergePreorderReq)
|
||
if err != nil {
|
||
log.Printf("主扫合单交易失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !mergePreorderResp.SuccessOrFail() {
|
||
log.Printf("主扫合单交易失败: %s\n", mergePreorderResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 2. 商户分账业务开通申请
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.ApplyLedgerMerResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
applyLedgerReq := &model.ApplyLedgerMerReqData{
|
||
Version: "1.0",
|
||
OrderNo: "12345678901234567890123456789012", // 32位订单号
|
||
OrgCode: "123456789012", // 机构代码
|
||
MerInnerNo: "1234567821", // 拉卡拉内部商户号
|
||
MerCupNo: "", // 银联商户号(与内部商户号二选一)
|
||
ContactMobile: "13311111111", // 联系手机号
|
||
SplitLowestRatio: 3.51, // 最低分账比例
|
||
SplitEntrustFileName: "授权委托书.pdf", // 授权委托书文件名
|
||
SplitEntrustFilePath: "path", // 授权委托书文件路径
|
||
SplitRange: consts.SPLIT_RANGE_ALL, // 分账范围(ALL全部交易分账,MARK标记交易分账)
|
||
RetUrl: "notifyUrl.com", // 回调URL
|
||
}
|
||
|
||
// 调用接口
|
||
expectResp, err := sdk.ApplyLedgerMer(applyLedgerReq)
|
||
if err != nil {
|
||
log.Printf("商户分账业务开通申请失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !expectResp.SuccessOrFail() {
|
||
log.Printf("商户分账业务开通申请失败: %s\n", expectResp.RetMsg)
|
||
}
|
||
```
|
||
|
||
### 3. 交易查询
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.TradeQueryResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
tradeQueryReq := &model.TradeQueryReqData{
|
||
MerchantNo: config.MerchantNo,
|
||
TermNo: config.TermNo,
|
||
OutTradeNo: "商户订单号", // 替换为实际的商户订单号
|
||
}
|
||
|
||
// 调用接口
|
||
tradeQueryResp, err := sdk.TradeQuery(tradeQueryReq)
|
||
if err != nil {
|
||
log.Printf("交易查询失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !tradeQueryResp.SuccessOrFail() {
|
||
log.Printf("交易查询失败: %s\n", tradeQueryResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 4. 订单分账
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.OrderSplitLedgerResponse](gctx.New(), cfgJson)
|
||
|
||
// 准备分账接收方数据
|
||
var recvDatas []*model.OrderSplitLedgerRecvDatas
|
||
// 可以向recvDatas数组中添加分账接收方信息
|
||
|
||
// 构建请求参数
|
||
splitLedgerReq := &model.OrderSplitLedgerReqData{
|
||
MerchantNo: config.MerchantNo,
|
||
LogDate: "", // 交易日期,格式为yyyyMMdd
|
||
LogNo: "", // 拉卡拉对账单流水号
|
||
OutSeparateNo: "", // 商户分账指令流水号
|
||
TotalAmt: "", // 分账总金额,单位为分
|
||
LklOrgNo: "", // 拉卡拉机构编号
|
||
CalType: consts.CAL_TYPE_AMOUNT, // 分账计算类型(0-按金额,1-按比例)
|
||
NotifyUrl: "", // 回调地址
|
||
RecvDatas: recvDatas, // 分账接收方数据
|
||
}
|
||
|
||
// 调用接口
|
||
splitLedgerResp, err := sdk.OrderSplitLedger(splitLedgerReq)
|
||
if err != nil {
|
||
log.Printf("订单分账失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !splitLedgerResp.SuccessOrFail() {
|
||
log.Printf("订单分账失败: %s\n", splitLedgerResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 5. 退款
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.RefundResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
refundReq := &model.RefundReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
OutTradeNo: "original_out_trade_no", // 原商户交易流水号
|
||
OutRefundNo: "your_refund_out_trade_no", // 退款商户流水号
|
||
RefundAmount: "100", // 退款金额,单位为分
|
||
TotalAmount: "100", // 原交易总金额,单位为分
|
||
RefundReason: "退款原因", // 退款原因
|
||
NotifyUrl: "https://your-notify-url.com", // 回调地址
|
||
}
|
||
|
||
// 调用接口
|
||
refundResp, err := sdk.Refound(refundReq)
|
||
if err != nil {
|
||
log.Printf("退款失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !refundResp.SuccessOrFail() {
|
||
log.Printf("退款失败: %s\n", refundResp.Msg)
|
||
}
|
||
|
||
// 处理成功响应
|
||
// 可以从refundResp.RespData中获取退款结果数据
|
||
```
|
||
|
||
### 6. 账户余额查询
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.BalanceQueryResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
balanceQueryReq := &model.BalanceQueryReqData{
|
||
MerchantNo: config.MerchantNo,
|
||
OrgNo: "", // 机构号
|
||
PayNo: "", // 支付单号
|
||
PayType: consts.PAY_TYPE_CARD, // 支付类型(CARD-卡支付,COUPON-优惠券支付,DISCOUNT-折扣支付,POINT-积分支付,MIX-混合支付)
|
||
MgtFlag: consts.MGT_FLAG_NO, // 管理标志(NO-普通交易,YES-管理交易)
|
||
}
|
||
|
||
// 调用接口
|
||
balanceQueryResp, err := sdk.BalanceQuery(balanceQueryReq)
|
||
if err != nil {
|
||
log.Printf("账户余额查询失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !balanceQueryResp.SuccessOrFail() {
|
||
log.Printf("账户余额查询失败: %s\n", balanceQueryResp.Msg)
|
||
}
|
||
```
|
||
|
||
## 错误处理
|
||
|
||
SDK使用两层错误处理机制,请确保同时检查网络错误和业务响应状态:
|
||
|
||
```go
|
||
// 1. 首先检查网络或SDK层面的错误
|
||
resp, err := sdk.SomeFunction(req)
|
||
if err != nil {
|
||
log.Printf("调用接口失败: %v\n", err)
|
||
// 处理网络错误或SDK内部错误
|
||
return err
|
||
}
|
||
|
||
// 2. 然后使用SuccessOrFail()方法判断业务响应是否成功
|
||
if !resp.SuccessOrFail() {
|
||
log.Printf("业务处理失败: %s\n", resp.Msg) // 或resp.RetMsg
|
||
// 处理业务失败情况
|
||
return errors.New("业务处理失败")
|
||
}
|
||
|
||
// 处理成功响应
|
||
// 使用resp获取返回的数据
|
||
```
|
||
|
||
### 7. 账户提现
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.WithdrawResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
withdrawReq := &model.WithdrawReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
OutTradeNo: "your_withdraw_out_trade_no", // 提现商户流水号
|
||
Amount: "10000", // 提现金额,单位为分
|
||
Currency: "CNY", // 货币类型
|
||
AccountType: "WECHAT", // 账户类型
|
||
}
|
||
|
||
// 调用接口
|
||
withdrawResp, err := sdk.Withdraw(withdrawReq)
|
||
if err != nil {
|
||
log.Printf("账户提现失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !withdrawResp.SuccessOrFail() {
|
||
log.Printf("账户提现失败: %s\n", withdrawResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 8. 商户进件
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.MerchantApplyResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
merchantApplyReq := &model.MerchantApplyReqData{
|
||
// 填写商户进件所需的各项参数
|
||
MerchantName: "商户名称",
|
||
ContactName: "联系人姓名",
|
||
ContactPhone: "联系电话",
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
merchantApplyResp, err := sdk.AddMer(merchantApplyReq)
|
||
if err != nil {
|
||
log.Printf("商户进件失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !merchantApplyResp.SuccessOrFail() {
|
||
log.Printf("商户进件失败: %s\n", merchantApplyResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 9. 商户进件信息查询
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.QueryMerResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
queryMerReq := &model.QueryMerRequestData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
queryMerResp, err := sdk.QueryMerchant(queryMerReq)
|
||
if err != nil {
|
||
log.Printf("商户进件信息查询失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !queryMerResp.SuccessOrFail() {
|
||
log.Printf("商户进件信息查询失败: %s\n", queryMerResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 10. 商户进件信息校验
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.MerValidateResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
merValidateReq := &model.MerValidateRequestData{
|
||
// 填写商户进件校验所需的各项参数
|
||
MerchantName: "商户名称",
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
merValidateResp, err := sdk.MerValidate(merValidateReq)
|
||
if err != nil {
|
||
log.Printf("商户进件信息校验失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !merValidateResp.SuccessOrFail() {
|
||
log.Printf("商户进件信息校验失败: %s\n", merValidateResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 11. 商户进件复议提交
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.ReConfSubmitResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
reConfSubmitReq := &model.ReConfSubmitRequestData{
|
||
// 填写商户进件复议所需的各项参数
|
||
MerchantNo: "your_merchant_no",
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
reConfSubmitResp, err := sdk.ReconsiderSubmit(reConfSubmitReq)
|
||
if err != nil {
|
||
log.Printf("商户进件复议提交失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !reConfSubmitResp.SuccessOrFail() {
|
||
log.Printf("商户进件复议提交失败: %s\n", reConfSubmitResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 12. 聚合预下单
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.PreorderResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
preOrderReq := &model.PreorderReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
OutTradeNo: "your_out_trade_no", // 商户交易流水号
|
||
AccountType: "WECHAT", // 账户类型
|
||
TransType: "71", // 交易类型
|
||
Amount: "100", // 金额,单位为分
|
||
Subject: "测试订单", // 订单标题
|
||
NotifyUrl: "https://your-notify-url.com", // 回调地址
|
||
}
|
||
|
||
// 调用接口
|
||
preOrderResp, err := sdk.PreOrder(preOrderReq)
|
||
if err != nil {
|
||
log.Printf("聚合预下单失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !preOrderResp.SuccessOrFail() {
|
||
log.Printf("聚合预下单失败: %s\n", preOrderResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 13. 文件上传查询
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.UploadFileResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
uploadFileReq := &model.UploadFileReqData{
|
||
// 填写文件上传查询所需的各项参数
|
||
// ...
|
||
}
|
||
|
||
// 调用接口
|
||
uploadFileResp, err := sdk.UploadFileQuery(uploadFileReq)
|
||
if err != nil {
|
||
log.Printf("文件上传查询失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !uploadFileResp.SuccessOrFail() {
|
||
log.Printf("文件上传查询失败: %s\n", uploadFileResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 14. 分账接收方创建申请
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.ApplyLedgerReceiverResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
applyLedgerReceiverReq := &model.ApplyLedgerReceiverReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
ReceiverType: "PERSON", // 接收方类型
|
||
ReceiverName: "接收方名称", // 接收方名称
|
||
ReceiverNo: "接收方编号", // 接收方编号
|
||
ReceiverAccNo: "接收方账号", // 接收方账号
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
applyLedgerReceiverResp, err := sdk.ApplyLedgerReceiver(applyLedgerReceiverReq)
|
||
if err != nil {
|
||
log.Printf("分账接收方创建申请失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !applyLedgerReceiverResp.SuccessOrFail() {
|
||
log.Printf("分账接收方创建申请失败: %s\n", applyLedgerReceiverResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 15. 分账关系绑定申请
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.ApplyBindResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
applyBindReq := &model.ApplyBindReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
ReceiverType: "PERSON", // 接收方类型
|
||
ReceiverNo: "接收方编号", // 接收方编号
|
||
BindType: "1", // 绑定类型
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
applyBindResp, err := sdk.ApplyBind(applyBindReq)
|
||
if err != nil {
|
||
log.Printf("分账关系绑定申请失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !applyBindResp.SuccessOrFail() {
|
||
log.Printf("分账关系绑定申请失败: %s\n", applyBindResp.Msg)
|
||
}
|
||
```
|
||
|
||
### 16. 可分账金额查询
|
||
|
||
```go
|
||
// 初始化特定响应类型的SDK
|
||
sdk := lklsdk.NewSDK[model.SplitBalanceResponse](gctx.New(), cfgJson)
|
||
|
||
// 构建请求参数
|
||
splitBalanceReq := &model.SplitBalanceReqData{
|
||
MerchantNo: "your_merchant_no", // 商户号
|
||
TermNo: "your_term_no", // 终端号
|
||
// ... 其他必要参数
|
||
}
|
||
|
||
// 调用接口
|
||
splitBalanceResp, err := sdk.QuerySplitBalance(splitBalanceReq)
|
||
if err != nil {
|
||
log.Printf("可分账金额查询失败: %v\n", err)
|
||
}
|
||
|
||
// 使用SuccessOrFail方法判断请求是否成功
|
||
if !splitBalanceResp.SuccessOrFail() {
|
||
log.Printf("可分账金额查询失败: %s\n", splitBalanceResp.Msg)
|
||
}
|
||
```
|
||
|
||
## 错误处理
|
||
|
||
SDK使用两层错误处理机制,请确保同时检查网络错误和业务响应状态:
|
||
|
||
```go
|
||
// 1. 首先检查网络或SDK层面的错误
|
||
resp, err := sdk.SomeFunction(req)
|
||
if err != nil {
|
||
log.Printf("调用接口失败: %v\n", err)
|
||
// 处理网络错误或SDK内部错误
|
||
return err
|
||
}
|
||
|
||
// 2. 然后使用SuccessOrFail()方法判断业务响应是否成功
|
||
if !resp.SuccessOrFail() {
|
||
log.Printf("业务处理失败: %s\n", resp.Msg) // 或resp.RetMsg
|
||
// 处理业务失败情况
|
||
return errors.New("业务处理失败")
|
||
}
|
||
|
||
// 处理成功响应
|
||
// 使用resp获取返回的数据
|
||
```
|
||
|
||
## 注意事项
|
||
|
||
1. 请妥善保管您的AppID、商户号、密钥等敏感信息
|
||
2. 确保网络环境稳定,避免请求超时
|
||
3. 建议添加请求重试机制,处理网络波动
|
||
4. 请遵循拉卡拉的接口规范,不要频繁调用接口
|
||
5. 如遇到问题,请参考拉卡拉官方文档或联系技术支持 |