This commit is contained in:
邹宗楠
2025-06-24 13:50:29 +08:00
parent 5b3ef2cd6d
commit 0599a21bce
42 changed files with 4192 additions and 26 deletions

View File

@@ -18,7 +18,7 @@ func TestCancelOrder(t *testing.T) {
}
func TestOrderGet(t *testing.T) {
result, err := api.OrderGet("4032856015365860035")
result, err := api.OrderGet("4097516027266349568")
products := result["products"].([]interface{})[0].([]interface{})
for _, product2 := range products {
product := product2.(map[string]interface{})

View File

@@ -27,7 +27,7 @@ func TestShopCategoryGet(t *testing.T) {
}
func TestShopGet222(t *testing.T) {
data, err := api.ShopGet("", 1257061574)
data, err := api.ShopGet("", 32267258880)
fmt.Println(data)
fmt.Println(err)
}

View File

@@ -159,7 +159,7 @@ func TestShopUpdate(t *testing.T) {
}
}
var StoreStatus2 = []int64{32267387627, 2267141486, 32267545390, 32267804789, 32267779555, 32267089395, 100000063963, 32267144442, 32267387614, 32267388565, 32267034104, 32267387606, 2267081269, 2234560558, 32267779547, 32267387580, 2167002619, 2234549766, 32267089396, 2233066023, 32267034093, 32267715495, 32267388573, 32267315069, 2267121512, 32267387577, 32267387576, 2234778219, 32267089418, 32267089423, 32267105194, 32267674067, 32267387552, 32267144455, 32267144480, 32267144470, 32267184056, 32267387550, 32267184051, 32267184034, 32267144462, 32267184070, 32267804790, 32267258834, 32267258858, 32267387531, 32267258862, 32267315053, 32267258872, 32267258878, 2267141513, 32267387525, 32267315061, 32267630601, 32267358120, 32267184082, 32267358106, 32267387534, 32267358101, 32267387488, 32267715496, 32267388570, 32267545402, 32267545380, 32267545394, 32267387579, 32267674064, 32267697568, 32267655030, 32267630644, 32267674065, 32267697561, 32267674042, 32267779551, 32267674060, 32267715494, 32267742248, 32267742251, 32267779552, 32267753661, 32267779542, 32267144483, 32267779558, 32267804811, 32267358115, 32267804787, 32267804791, 32267804793, 32267804800, 32267812968, 32267804803, 32267742242, 100000048520, 100000107370, 100000104868, 200000143541, 100000190484, 100000190475, 2122964557, 1119844487, 2132873395, 505866454, 1102408916, 506287807, 506322630, 1109714045, 507377485, 507621023, 1124508293, 1124489923, 1128314567, 1137321209, 1138084276, 508376256, 1139471614, 1140171041, 508163472, 1139765248, 1140168573, 1143733509, 1145229605, 509156468, 1144562343, 509351958, 32267655046, 1151130808, 1155331892, 1155432211, 1161746045, 1164043546, 512276503, 513523362, 514710033}
var StoreStatus2 = []int64{32267258880}
var status = map[int]string{1: "休息中", 2: "可预订", 3: "营业中", 4: "停营业"}
func TestShopBusStatusGet(t *testing.T) {

View File

@@ -30,11 +30,11 @@ func init() {
// 天天果园
//api = New("c45e6510-00ba-4be2-977e-bcb9c9792cc7", "5d5577a2506f41b8b4ec520ba83490f5", "0b01b9eeb15b41dab1c3d05d95c17a26")
// 京东果园 320406
//api = New("1e87595b-e850-4ba4-9ee0-53bcfe383a4f", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
api = New("de4a9818-b171-41ed-ba37-0b060cad001f", "1dba76d40cac446ca500c0391a0b6c9d", "a88d031a1e7b462cb1579f12e97fe7f4")
// 京东白货
//api = New("9053e4fd-4e0e-4e9e-8ab1-f348e5cbf3e7", "4602bd4b84984186815dbc03299c7094", "386ab19719d9470487011217d0c57349")
// 果切 379599
api = New("8a843f5c-6c75-4604-9976-04c1aae3decc", "f2ed33075faf4773a47e065acd79532b", "aed14cbbecac4456843570e90c5f46ec")
//api = New("8a843f5c-6c75-4604-9976-04c1aae3decc", "f2ed33075faf4773a47e065acd79532b", "aed14cbbecac4456843570e90c5f46ec")
// 李氏水果 346254
//api = New("c7c41cb6-6db4-4f67-a864-ca5f524653d0", "13493b4a951945f689dcc989b6693631", "7e28a37be43a430bb5928c835e482fe2")
// 381564

View File

@@ -32,7 +32,7 @@ func TestPickUp(t *testing.T) {
func TestOrderQuery(t *testing.T) {
jdParams := map[string]interface{}{
"orderId": "2429933823001193",
"orderId": "316972178380",
}
result, totalCount, err := api.OrderQuery(jdParams)
if err != nil {

View File

@@ -0,0 +1,211 @@
package lakala
import (
"encoding/base64"
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"strings"
"time"
)
type API struct {
appID string
serialNo string
sM4Key string
clientId string
clientSecret string
incomingToken string // 进件相关token
incomingExpire int64 // 进件token过期时间
modifiedToken string // 改件token
modifiedExpire int64 // 改件过期时间
orgCode string // 机构代码
client *http.Client
config *platformapi.APIConfig
}
func New(appID, serialNo, sM4Key, clientId, clientSecret, incomingToken, changeToken, orgCode string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
appID: appID,
serialNo: serialNo,
sM4Key: sM4Key,
clientId: clientId,
clientSecret: clientSecret,
incomingToken: incomingToken,
incomingExpire: 0,
modifiedToken: changeToken,
modifiedExpire: 0,
orgCode: orgCode,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
// AccessAPI form表单格式
func (a *API) AccessAPI(baseUrl, action, method string, pathParam string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
a.CheckToken()
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
var request *http.Request
if http.MethodPost == method {
// 全路径请求参数
fullURL := utils.GenerateGetURL(baseUrl, action, nil)
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(utils.Map2URLValues(bizParams).Encode()))
request.Header.Set("charset", "UTF-8")
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else {
getUrl := utils.GenerateGetURL(baseUrl, action, nil)
if pathParam != "" {
getUrl = getUrl + fmt.Sprintf("/%s", pathParam)
}
if bizParams != nil {
getUrl = utils.GenerateGetURL(getUrl, "", bizParams)
}
request, _ = http.NewRequest(http.MethodGet, getUrl, nil)
}
switch IncomingTokenActive[action] {
case IncomingToken:
request.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.incomingToken))
case ModifiedToken:
request.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.modifiedToken))
case NotToken:
if bizParams["grant_type"].(string) == "password" {
base64Unicode := fmt.Sprintf("%s:%s", a.clientId, a.clientSecret)
request.Header.Set("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(base64Unicode))))
}
}
return request
},
a.config,
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
if err == nil {
//returnCode := utils.Interface2String(jsonResult1["trxstatus"])
//if returnCode != "200" {
// errLevel = platformapi.ErrLevelGeneralFail
// err = utils.NewErrorCode(utils.Interface2String(jsonResult1["errmsg"])+utils.Interface2String(jsonResult1["retmsg"]), returnCode)
//}
retVal = jsonResult1
}
return errLevel, err
})
return retVal, err
}
// AccessAPI2 json格式
func (a *API) AccessAPI2(baseUrl, action, method string, pathParam string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
a.CheckToken()
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
var request *http.Request
if http.MethodPost == method {
// 全路径请求参数
data, _ := json.Marshal(bizParams)
fullURL := utils.GenerateGetURL(baseUrl, action, nil)
if pathParam != "" {
fullURL = fullURL + fmt.Sprintf("/%s", pathParam)
}
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data)))
} else {
getUrl := utils.GenerateGetURL(baseUrl, action, nil)
if pathParam != "" {
getUrl = getUrl + fmt.Sprintf("/%s", pathParam)
}
if bizParams != nil {
getUrl = utils.GenerateGetURL(getUrl, "", bizParams)
}
request, _ = http.NewRequest(http.MethodGet, getUrl, nil)
}
//if action == IncomingAction {
request.Header.Set("Content-Type", "application/json")
//}
switch IncomingTokenActive[action] {
case IncomingToken:
request.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.incomingToken))
case ModifiedToken:
request.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.modifiedToken))
case SignToken:
request.Header.Set("Authorization", fmt.Sprintf("LKLAPI-SHA256withRSA %s", a.modifiedToken))
case NotToken:
if bizParams["grant_type"].(string) == "password" {
base64Unicode := fmt.Sprintf("%s:%s", a.clientId, a.clientSecret)
request.Header.Set("Authorization", fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(base64Unicode))))
}
}
return request
},
a.config,
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
if err == nil {
retVal = jsonResult1
}
return errLevel, err
})
return retVal, err
}
// AccessAPISign 支付相关需要签名
func (a *API) AccessAPISign(baseUrl, action, method string, pathParam string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
a.CheckToken()
Authorization, err := a.signParamRSA(bizParams, LaKaLaPrivateKey)
if err != nil {
return nil, err
}
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
var request *http.Request
if http.MethodPost == method {
// 全路径请求参数
data, _ := json.Marshal(bizParams)
fullURL := utils.GenerateGetURL(baseUrl, action, nil)
if pathParam != "" {
fullURL = fullURL + fmt.Sprintf("/%s", pathParam)
}
request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data)))
} else {
getUrl := utils.GenerateGetURL(baseUrl, action, nil)
if pathParam != "" {
getUrl = getUrl + fmt.Sprintf("/%s", pathParam)
}
if bizParams != nil {
getUrl = utils.GenerateGetURL(getUrl, "", bizParams)
}
request, _ = http.NewRequest(http.MethodGet, getUrl, nil)
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", Authorization)
request.Header.Set("Accept", "application/json")
return request
},
a.config,
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
if jsonResult1 == nil {
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
}
if err == nil {
retVal = jsonResult1
}
return errLevel, err
})
return retVal, err
}
func (a *API) CheckToken() {
if a.incomingToken == "" || a.incomingExpire-time.Now().Unix() < 0 {
a.IncomingToken()
}
if a.modifiedToken == "" || a.modifiedExpire-time.Now().Unix() < 0 {
a.ModifiedToken(UserName, Password)
}
}

View File

@@ -0,0 +1,139 @@
package lakala
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"time"
)
// QueryBillBalance 查询账户余额
func (a *API) QueryBillBalance(param *QueryBillBalanceReq) (*QueryBillBalanceResp, error) {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": utils.GetUUID(),
"ver": "1.0.0",
"timestamp": time.Now().Unix(),
}
result, err := a.AccessAPISign(BillTestUrl, BillQuery, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["retCode"].(string) != Success {
return nil, fmt.Errorf(result["retMsg"].(string))
}
bodyResult, err := json.Marshal(result["respData"])
if err != nil {
return nil, err
}
resp := &QueryBillBalanceResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// EwalletWithdrawD1 账户D1提现
func (a *API) EwalletWithdrawD1(param *EwalletWithdrawD1Req) (string, string, error) {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": utils.GetUUID(),
"ver": "1.0.0",
"timestamp": time.Now().Unix(),
}
result, err := a.AccessAPISign(BillTestUrl, BillDrawD1, http.MethodPost, "", reqParameter)
if err != nil {
return "", "", err
}
if result["retCode"].(string) != Success {
return "", "", fmt.Errorf(result["retMsg"].(string))
}
return result["respData"].(map[string]string)["drawJnl"], result["respData"].(map[string]string)["merOrderNo"], nil
}
// EwalletWithdrawQuery 提现结果查询
func (a *API) EwalletWithdrawQuery(param *EwalletWithdrawQueryReq) (*EwalletWithdrawQueryResp, error) {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": utils.GetUUID(),
"ver": "1.0.0",
"timestamp": time.Now().Unix(),
}
result, err := a.AccessAPISign(BillTestUrl, BillDrawD1Query, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["retCode"].(string) != Success {
return nil, fmt.Errorf(result["retMsg"].(string))
}
bodyResult, err := json.Marshal(result["respData"])
if err != nil {
return nil, err
}
resp := &EwalletWithdrawQueryResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// SettleDrawPattern 设置提款模式
func (a *API) SettleDrawPattern(param *SettleDrawPatternReq) error {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": utils.GetUUID(),
"ver": "1.0.0",
"timestamp": time.Now().Unix(),
}
result, err := a.AccessAPISign(BillTestUrl, BillSettleProfile, http.MethodPost, "", reqParameter)
if err != nil {
return err
}
if result["retCode"].(string) != Success {
return fmt.Errorf(result["retMsg"].(string))
}
return nil
}
// EwalletSettleQuery 提款模式查询
func (a *API) EwalletSettleQuery(bmcpNo, mercId string) (*EwalletSettleQueryResp, error) {
reqParameter := map[string]interface{}{
"reqData": map[string]string{"bmcpNo": bmcpNo, "mercId": mercId},
"reqId": utils.GetUUID(),
"ver": "1.0.0",
"timestamp": time.Now().Unix(),
}
result, err := a.AccessAPISign(BillTestUrl, BillSettleQuery, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["retCode"].(string) != Success {
return nil, fmt.Errorf(result["retMsg"].(string))
}
bodyResult, err := json.Marshal(result["respData"])
if err != nil {
return nil, err
}
resp := &EwalletSettleQueryResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}

View File

@@ -0,0 +1,101 @@
package lakala
const (
BillTestUrl = "https://test.wsmsd.cn/sit/api/v2/laep/industry"
BillProdUrl = "https://s2.lakala.com/api/v2/laep/industry"
BillQuery = "ewalletBalanceQuery" // 账户余额查询
BillDrawD1 = "ewalletWithdrawD1" // 账户余额D1提现
BillDrawD1Query = "ewalletWithdrawQuery" // 账户余额D1提现结果查询
BillSettleProfile = "ewallet/settleProfile" // 提款模式设置
BillSettleQuery = "ewallet/settleQuery" // 提款模式查询
)
// QueryBillBalanceReq 账户余额查询请求参数
type QueryBillBalanceReq struct {
OrgNo string `json:"orgNo"` // bmcp机构号 是
MerchantNo string `json:"merchantNo"` // 商户号 或 receiveNo 或 商户用户编号 是
PayNo string `json:"payNo"` // 账号若该参数上送则payType将无效
PayType string `json:"payType"` // 账号类型01收款账户02付款账户03分账商户账户04分账接收方账户05充值代付账户06结算代付账户- 未上送则默认为01 否
MgtFlag string `json:"mgtFlag"` // (待上线) 账户标志01:一般户 03:子虚户)- 未上送则默认为01 否
}
// QueryBillBalanceResp 账户余额查询返回参数
type QueryBillBalanceResp struct {
PayNo string `json:"payNo"` // 账号
PayType string `json:"payType"` // 账户类型
AcctSt string `json:"acctSt"` // 账户状态 CLOSE 销户 NORMAL 正常 FREEZE 冻结 STOPPAY 止付
ForceBalance string `json:"forceBalance"` // 预付余额(单位元)
HisBalance string `json:"hisBalance"`
ReBalance string `json:"reBalance"` // 实时余额(单位元)
CurBalance string `json:"curBalance"` // 当前可用余额(单位元)
}
// EwalletWithdrawD1Req 账户体现
type EwalletWithdrawD1Req struct {
OrgNo string `json:"orgNo"` // bmcp机构号 是 String(32) 机构号
MerchantNo string `json:"merchantNo"` // 商户号 是 String(32) 822商户号 SR分账接收方编号
DrawAmt string `json:"drawAmt"` // 提现金额(单位:元) 是 String(32)
NotifyUrl string `json:"notifyUrl"` // 通知地址 否 String(256)
MerOrderNo string `json:"merOrderNo"` // 商户订单号(商户系统唯一) 否 String(256)
PayNo string `json:"payNo"` // 账号若该参数上送则payType将无效 否 String(32)
PayType string `json:"payType"` // 账号类型01收款账户04分账接收方账户未上送则默认为01 是 String(32) 分账接收方提现时需填04
Remark string `json:"remark"` // 备注信息 否 String(64)
Summary string `json:"summary"` // 摘要 否 String(64)
BankId string `json:"bankId"` // 结算银行ID 否 String(32)
}
// EwalletWithdrawQueryReq 提现结果查询请求参数
type EwalletWithdrawQueryReq struct {
OrgNo string `json:"orgNo"` // bmcp机构号
MerchantNo string `json:"merchantNo"` // 商户号
DrawJnl string `json:"drawJnl"` // 提款流水号(二选一)
MerOrderNo string `json:"merOrderNo"` // 商户订单号(二选一)
}
type EwalletWithdrawQueryResp struct {
EwalletId string `json:"ewalletId"` // 钱包ID
DrawJnl string `json:"drawJnl"` // 提款流水号
ReqDate string `json:"reqDate"` // 请求日期
DrawAmt string `json:"drawAmt"` // 提款金额(元):含手续费
DrawFee string `json:"drawFee"` // 手续费(元)
DrawMode string `json:"drawMode"` // 提款模式(D0/D1)
BatchAutoSettle string `json:"batchAutoSettle"` // 结算模式01主动提款 02余额自动结算 03 交易自动结算)
BatchNo string `json:"batchNo"` // 自动结算批次号
AcctNo string `json:"acctNo"` // 结算账户号(脱敏)
AcctName string `json:"acctName"` // 结算账户名(脱敏)
DrawState string `json:"drawState"` // 提款状态 DRAW.ACCEPTED 提款已受理 DRAW.FREEZE 提款冻结DRAW.PROCESSING 提款处理中DRAW.SUCCESS 提款成功DRAW.FAILED 提款失败
Memo string `json:"memo"` // 结果信息
MerOrderNo string `json:"merOrderNo"` // 商户订单号
SettleNo string `json:"settleNo"` // 结算流水号
BankNo string `json:"bankNo"` // 银行行号
NbkName string `json:"nbkName"` // 银行名称
MercId string `json:"mercId"` // 商户号
CompleteTime string `json:"completeTime"` // 完成时间
CreatedTime string `json:"createdTime"` // 创建时间
}
// SettleDrawPatternReq 提款模式设置
type SettleDrawPatternReq struct {
BmcpNo string `json:"bmcpNo"` // BMCP机构号 是 String(32)
MercId string `json:"mercId"` // 822商户号 或 receiveNo 是 String(32)
SettleType string `json:"settleType"` // 提款模式01主动提款 02余额自动结算 03交易自动结算 是 String(32)
SettleTime string `json:"settleTime"` // 余额自动结算时间(小时)- 默认值06。如08:00-09:00到账则传入08。 否 String(2) 针对02余额自动结算生效
SettleCircle string `json:"settleCircle"` // 交易自动结算周期D1/T1 否 String(2) 针对03交易自动结算生效
PayType string `json:"payType"` // 结算账户类型01收款账户 04 分账接收方账户) 否 String(2) 针对02余额自动结算,03交易自动结算生效
NotifyUrl string `json:"notifyUrl"` // 提款通知URL 否 String(64) 提款模式0203生效
RetainedAmt string `json:"retainedAmt"` // 留存金额(单位:元) 否 String(64) 提款模式02生效
Remark string `json:"remark"` // 备注 否 String(64)
Summary string `json:"summary"` // 摘要 否 String(64)
}
// EwalletSettleQueryResp 提款模式查询
type EwalletSettleQueryResp struct {
EwalletId string `json:"ewalletId"` // 钱包ID 是
SettleType string `json:"settleType"` // 提款模式01主动提款 02自动结算03交易自动结算
SettleTime string `json:"settleTime"` // 结算时间(小时) 是
SettleCircle string `json:"settleCircle"` // 结算周期 否
PayType string `json:"payType"` // 结算账户类型 否
NotifyUrl string `json:"notifyUrl"` // 提款通知URL 否
RetainedAmt string `json:"notifyUrl"` // 留存金额(单位:元) 否
}

View File

@@ -0,0 +1,53 @@
package lakala
import (
"fmt"
"git.rosy.net.cn/baseapi/utils"
"testing"
)
// TestQueryBillBalance 查询账户余额
func TestQueryBillBalance(t *testing.T) {
api.QueryBillBalance(&QueryBillBalanceReq{
OrgNo: "1",
MerchantNo: "8221000581200BS",
PayNo: "",
PayType: "",
MgtFlag: "",
})
}
// TestEwalletWithdrawD1 账户D1体现
func TestEwalletWithdrawD1(t *testing.T) {
api.EwalletWithdrawD1(&EwalletWithdrawD1Req{
OrgNo: "1",
MerchantNo: "8221000581200BS",
DrawAmt: "10",
NotifyUrl: "test",
MerOrderNo: "hxmkl20220816900003",
PayNo: "",
PayType: "",
Remark: "",
Summary: "",
BankId: "",
})
}
// TestEwalletWithdrawQuery 提现结果查询
func TestEwalletWithdrawQuery(t *testing.T) {
api.EwalletWithdrawQuery(&EwalletWithdrawQueryReq{
OrgNo: "1",
MerchantNo: "8221000581200BS",
DrawJnl: "220816141533426266212404",
MerOrderNo: "",
})
}
// TestEwalletSettleQuery 提款模式查询
func TestEwalletSettleQuery(t *testing.T) {
api.EwalletSettleQuery("1", "82229005943096B")
}
func TestTime2TimeStrByFormat(t *testing.T) {
fmt.Println(utils.Str2Time("2022-04-06 17:01:05"))
}

View File

@@ -0,0 +1,189 @@
package lakala
// SeparateCallback 商户分账创建/修改回调
type SeparateCallback struct {
ApplyId string `json:"applyId"`
MerInnerNo string `json:"merInnerNo"`
MerCupNo string `json:"merCupNo"`
EntrustFileName string `json:"entrustFileName"`
AuditStatus string `json:"auditStatus"`
Remark string `json:"remark"`
AuditStatusText string `json:"auditStatusText"`
EntrustFilePath string `json:"entrustFilePath"`
}
// SeparateBindCallback 分账关系绑定回调
type SeparateBindCallback struct {
OptType string `json:"optType"` // 操作类型
ApplyId string `json:"applyId"` // 申请编号
MerCupNo string `json:"merCupNo"` // 商户号
EntrustFileName string `json:"entrustFileName"` // 附件
AuditStatus string `json:"auditStatus"` // 附件路径
MerInnerNo string `json:"merInnerNo"` // 分账商户内部商户号
ReceiverNo string `json:"receiverNo"` // 分账接收方编号
Remark string `json:"remark"` // 备注
AuditStatusText string `json:"auditStatusText"` // 审核状态
EntrustFilePath string `json:"entrustFilePath"` // 附件路径
}
// SeparateResult 分账结果通知
type SeparateResult struct {
SeparateNo string `json:"separate_no"` // 分账指令流水号
OutSeparateNo string `json:"out_separate_no"` // 商户分账指令流水号
CmdType string `json:"cmd_type"` // SEPARATE分账 CANCEL分账撤销FALLBACK分账回退
LogNo string `json:"log_no"` // 拉卡拉对账单流水号
LogDate string `json:"log_date"` // 交易日期
CalType string `json:"cal_type"` // 分账计算类型 0 按照指定金额。1 按照指定比例,默认 0
SeparateType string `json:"separate_type"` // 分账接收类型 0 全部分账到商户本身。1 分账到多方,默认 1
TotalAmt string `json:"total_amt"` // 发生总金额
Status string `json:"status"` // 分账状态
SeparateDate string `json:"separate_date"` // 分账日期
FinishDate string `json:"finish_date"` // 完成日期
FinalStatus string `json:"final_status"`
DetailDatas []struct {
RecvMerchantNo string `json:"recv_merchant_no"` // 接收方商户号
RecvNo string `json:"recv_no"` // 接收方编号
Amt string `json:"amt"` // 分账金额
} `json:"detail_datas"`
}
// EwalletWithdrawD1CallBack 帐管家提现结果通知
type EwalletWithdrawD1CallBack struct {
PayNo string `json:"payNo"`
EwalletId string `json:"ewalletId"` // 钱包ID
DrawJnl string `json:"drawJnl"` // 提款流水号
ReqDate string `json:"reqDate"` // 请求日期
DrawAmt string `json:"drawAmt"` // 提款金额(元):含手续费
DrawFee string `json:"drawFee"` // 手续费(元)
DrawMode string `json:"drawMode"` // 提款模式(D0/D1)
BatchAutoSettle string `json:"batchAutoSettle"` // 结算模式01主动提款 02余额自动结算 03 交易自动结算)
BatchNo string `json:"batchNo"` // 自动结算批次号
AcctNo string `json:"acctNo"` // 结算账户号(脱敏)
AcctName string `json:"acctName"` // 结算账户名(脱敏)
DrawState string `json:"drawState"` // 提款状态 DRAW.ACCEPTED 提款已受理 DRAW.FREEZE 提款冻结DRAW.PROCESSING 提款处理中DRAW.SUCCESS 提款成功DRAW.FAILED 提款失败
Memo string `json:"memo"` // 结果信息
MerOrderNo string `json:"merOrderNo"` // 商户订单号
SettleNo string `json:"settleNo"` // 结算流水号
BankNo string `json:"bankNo"` // 银行行号
NbkName string `json:"nbkName"` // 银行名称
MercId string `json:"mercId"` // 商户号
CompleteTime string `json:"completeTime"` // 完成时间
CreatedTime string `json:"createdTime"` // 创建时间
}
// QueryOrderCallBackResp 查询订单详情
type QueryOrderCallBackResp struct {
PayOrderNo string `json:"pay_order_no"` // M String 64 支付订单号 21070211012001970631000383039
OutOrderNo string `json:"out_order_no"` // M String 32 商户订单号 12345678
ChannelId string `json:"channel_id"` // M String 32 渠道号
TransMerchantNo string `json:"trans_merchant_no"` // C String 32 交易商户号
TransTermNo string `json:"trans_term_no"` // C String 16 交易终端号
MerchantNo string `json:"merchant_no"` // M String 32 结算商户号(合单订单中该结算商户号为主单名义上结算商户号) 822126090640003
TermNo string `json:"term_no"` // M String 16 结算终端号(合单订单中该结算商户号为主单名义上结算终端号)
OrderStatus string `json:"order_status"` // M String 2 订单状态 0:待支付 1:支付中 2:支付成功 3:支付失败 4:已过期 5:已取消 6:部分退款或者全部退款 7:订单已关闭枚举
OrderInfo string `json:"order_info"` // C String 100 订单描述
TotalAmount int64 `json:"total_amount"` // M long 12 订单金额,单位:分 200
OrderCreateTime string `json:"order_create_time"` // M String 14 订单创建时间 格式yyyyMMddHHmmss
OrderEfficientTime string `json:"order_efficient_time"` // M String 14 订单有效时间 格式yyyyMMddHHmmss
SettleType string `json:"settle_type"` // C String 4 结算类型(非合单) “0”或者空常规结算方式
SplitMark string `json:"split_mark"` // C String 2 合单标识 “1”为合单不填默认是为非拆单
SplitInfo []SplitInfoCallbackObj `json:"split_info"` // C List<交易拆单信息 详细字段见split_info字段说明
OrderTradeInfo OrderTradeInfoListCallBackObj `json:"order_trade_info"` // M List<>订单交易信息列表 list单元为ObjectObject对象包含如下字段 ,按交易完成时间逆序排列
CounterRemark string `json:"counter_remark"` // C String 128 收银台备注
}
type SplitInfoCallbackObj struct {
SubTradeNo string `json:"sub_trade_no"` // 子单交易流水号 M String(32) 子单交易流水号
SubLogNo string `json:"sub_log_no"` // 子单对账单流水号 M String(14) 子单对账单流水号
OutSubOrderNo string `json:"out_sub_order_no"` // 外部子订单号 M String(32) 商户子订单号
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的银联商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
Amount string `json:"amount"` // 金额 M String(12) 单位分,整数型字符
}
type OrderTradeInfoListCallBackObj struct {
TradeNo string `json:"trade_no"` // M String 32 交易流水号 2021070266210002570007或者 21080302570007
LogNo string `json:"log_no"` // M String 14 对账单流水号 66210002570007或者 21080302570007
TradeRefNo string `json:"trade_ref_no"` // M String 12 交易参考号 080302570007,仅busi_type为UPCARD时返回
TradeType string `json:"trade_type"` // M String 16 交易类型 PAY-消费 REFUND-退款 CANCEL-撤销
TradeStatus string `json:"trade_status"` // M String 2 支付状态 返回状态 S:成功 F:失败 C:被冲正 U:预记状态 X:发送失败 T: 发送超时 P: 处理中
TradeAmount int64 `json:"trade_amount"` // M long 12 交易金额,单位:分 200
PayerAmount int64 `json:"payer_amount"` // M long 12 付款人实际支付金额,单位:分
UserId1 string `json:"user_id1"` // C String 64 用户标识1 微信sub_open_id 支付宝buyer_logon_id买家支付宝账号
UserId2 string `json:"user_id2"` // C String 64 用户标识2 微信openId 支付宝buyer_user_id 银联user_id
BusiType string `json:"busi_type"` // M String 16 支付业务类型UPCARD-银行卡SCPAY-扫码支付DCPAY-数币支付ONLINE-线上支付
TradeTime string `json:"trade_time"` // C String 14 交易完时间 格式yyyyMMddHHmmss
AccTradeNo string `json:"acc_trade_no"` // C String 32 付款受理交易流水号 支付宝流水号、微信流水号
PayerAccountNo string `json:"payer_account_no"` // C String 32 付款人账号
PayerName string `json:"payer_name"` // C String 32 付款人名称仅ONLINE交易返回
PayerAccountBank string `json:"payer_account_bank"` // C String 32 付款账号开户行
AccType string `json:"acc_type"` // C String 2 账户类型 busi_type为UPCARD时返回00-借记卡,01-贷记卡,02-准贷记卡,03-预付卡busi_type为SCPAY时返回00不确定,02-微信零钱,03-支付宝花呗,04-支付宝钱包,99-未知
PayMode string `json:"pay_mode"` // C String 2 付款方式 busi_type为SCPAY时返回UQRCODEPAY-银联、WECHAT-微信、ALIPAY-支付宝
ClientBatchNo string `json:"client_batch_no"` // C String 6 终端批次号 刷卡交易终端批次号只有busi_type为UPCARD时返回
ClientSeqNo string `json:"client_seq_no"` // C String 6 终端流水号 刷卡交易终端流水号只有busi_type为UPCARD时返回
SettleMerchantNo string `json:"settle_merchant_no"` // C String 32 结算商户号
SettleTermNo string `json:"settle_term_no"` // C String 16 结算终端号
OriginTradeNo string `json:"origin_trade_no"` // C String 32 原交易流水号(扫码交易的退款场景中,对应原交易流水号) 2021070266210002570007
AuthCode string `json:"auth_code"` // C String 64 快捷签约协议号
BankType string `json:"bank_type"` // C String 64 付款银行
AccSettleAmount string `json:"acc_settle_amount"` // C String 12 账户端结算金额
AccMdiscountAmount string `json:"acc_mdiscount_amount"` // C String 12 商户侧优惠金额(账户端)
AccDiscountAmount string `json:"acc_discount_amount"` // C String 12 账户端优惠金额
AccOtherDiscountAmount string `json:"acc_other_discount_amount"` // C String 12 账户端其它优惠金额
CounterRemark string `json:"counter_remark"` // C String 128 收银台备注
//ResultDescstring string `json:"result_descstring"` // (待上线) C String 32 交易结果描述
}
// PayStatusCallBack 拉卡拉支付回调
type PayStatusCallBack struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号(交易请求接口中商户号)
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 M String(64)
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号 M String(32) 拉卡拉交易流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号 M String(14) trade_no的后14位
AccTradeNo string `json:"acc_trade_no"` // 账户端交易订单号 M String(32) 账户端交易订单号
AccountType string `json:"account_type"` // 钱包类型 M String(32) 微信WECHAT 支付宝ALIPAY 银联UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 数字人民币-DCPAY
SettleMerchantNo string `json:"settle_merchant_no"` // 结算商户号 C String(32) 拉卡拉分配的商户号
SettleTermNo string `json:"settle_term_no"` // 结算终端号 C String(32) 拉卡拉分配的业务终端号
TradeStatus string `json:"trade_status"` // 交易状态 M String(16) INIT-初始化 CREATE-下单成功 SUCCESS-交易成功 FAIL-交易失败 DEAL-交易处理中 UNKNOWN-未知状态 CLOSE-订单关闭 PART_REFUND-部分退款 REFUND-全部退款 REVOKED-订单撤销
TotalAmount string `json:"total_amount"` // 订单金额 M String(12) 单位分,整数数字型字符
PayerAmount string `json:"payer_amount"` // 付款人实付金额 C String(12) 付款人实付金额,单位分
AccSettleAmount string `json:"acc_settle_amount"` // 账户端结算金额 C String(12) 账户端应结订单金额,单位分 ,账户端应结订单金额=付款人实际发生金额+账户端优惠金额
AccMdiscountAmount string `json:"acc_mdiscount_amount"` // 商户侧优惠金额(账户端) C String(12) 商户优惠金额,单位分
AccDiscountAmount string `json:"acc_discount_amount"` // 账户端优惠金额 C String(12) 账户端优惠金额,单位分
AccOtherDiscountAmount string `json:"acc_other_discount_amount"` // 账户端其它优惠金额 C String(12) 账户端返回账户端其它优惠金额,单位分
TradeTime string `json:"trade_time"` // 交易完成时间 C String(14) 实际支付时间。yyyyMMddHHmmss
UserId1 string `json:"user_id1"` // 用户标识1 C String(128) 微信sub_open_id, 支付宝buyer_logon_id买家支付宝账号
UserId2 string `json:"user_id2"` // 用户标识2 C String(128) 微信openId,支付宝buyer_user_id,银联user_id
AccActivityId string `json:"acc_activity_id"` // 活动 ID C String(32) 在账户端商户后台配置的批次 ID
BankType string `json:"bank_type"` // 付款银行 C String(128) 付款银行
CardType string `json:"card_type"` // 银行卡类型 C String(16) 00借记 01贷记 02微信零钱 03支付宝花呗 04支付宝其他 05数字货币 06拉卡拉支付账户 99未知 sha
Remark string `json:"remark"` // 备注 C String(128)
HbFqPayInfo HbFqPayInfoObj `json:"hb_fq_pay_info"` // 花呗分期支付信息 C Object
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
OutSplitRspInfos []OutSplitRspInfosObj `json:"out_split_rsp_infos"` // 合单信息 C List<>
DiscountGoodsDetail string `json:"discount_goods_detail"` // 单品券优惠的商品优惠信息 C String(1024)
}
// HbFqPayInfoObj 花呗分期
type HbFqPayInfoObj struct {
FqAmount string `json:"fq_amount"` // 分期金额 M String(12) 单位分,整数数字型字符
UserInstallNum string `json:"user_install_num"` // 分期期数 M String(12) 分期期数,整数数字型字
}
// OutSplitRspInfosObj 合单信息内容
type OutSplitRspInfosObj struct {
SubTradeNo string `json:"sub_trade_no"` // 子单拉卡拉流水号 M String(32)
SubLogNo string `json:"sub_log_no"` // 子单对账流水号 M String(12)
OutSubTradeNo string `json:"out_sub_trade_no"` // 子单外部流水号 M String(32)
MerchantNo string `json:"merchant_no"` // 子单商户号 M String(32)
TermNo string `json:"term_no"` // 子单终端号 M String(8)
Amount string `json:"amount"` // 子单金额 M String(12) 单位:分
}
// DiscountGoodsDetail 优惠信息
type DiscountGoodsDetail struct {
GoodsId string `json:"goods_id"` // 商品id M String
GoodsName string `json:"goods_name"` // 商品名称 C String
DiscountAmount string `json:"discount_amount"` // 优惠金额 C String
VoucherId string `json:"voucher_id"` // 优惠id C String
}

View File

@@ -0,0 +1,350 @@
package lakala
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net/http"
)
// MerchantIncoming 商户进件接口
func (a *API) MerchantIncoming(incoming *MerchantIncomingReq) (string, string, error) {
data := utils.Struct2Map(incoming, "", false)
result, err := a.AccessAPI2(BaseTestUrl, IncomingAction, http.MethodPost, "", data)
if err != nil {
return "", "", err
}
return result["merchantNo"].(string), result["status"].(string), nil
}
// GetMerchantInfo 获取商户详细信息
func (a *API) GetMerchantInfo(customerNo string) (*MerchantObj, error) {
data := map[string]interface{}{"customerNo": customerNo}
result, err := a.AccessAPI2(BaseTestChangeUrl, GetMerchantInfo, http.MethodPost, "", data)
if err != nil {
return nil, err
}
if result["code"].(string) != Success {
return nil, fmt.Errorf(result["message"].(string))
}
merchant := &MerchantObj{}
merchantInfo, _ := json.Marshal(result["data"])
json.Unmarshal(merchantInfo, merchant)
return merchant, nil
}
// GetOrganizationCode 获取城市组织代码 parentCode = 1 查所有,城市code看看和我们系统一致不
func (a *API) GetOrganizationCode(parentCode string) ([]*OrganizationList, error) {
result, err := a.AccessAPI(BaseTestUrl, OrganizationAction, http.MethodGet, parentCode, nil)
if err != nil {
return nil, err
}
if result[ResultKey] != nil {
byteBank, err := json.Marshal(result[ResultKey])
if err != nil {
return nil, err
}
bankList := make([]*OrganizationList, 0, 0)
if err = json.Unmarshal(byteBank, &bankList); err != nil {
return nil, err
}
return bankList, err
}
return nil, fmt.Errorf("接口[%s],未查询到数据", OrganizationAction)
}
// GetBankList 银行列表查询
func (a *API) GetBankList(areaCode, bankName string) ([]*BankListResult, error) {
param := map[string]interface{}{
"areaCode": areaCode,
}
if bankName != "" {
param["bankName"] = bankName
}
result, err := a.AccessAPI(BaseTestUrl, BankList, http.MethodGet, "", param)
if err != nil {
return nil, err
}
if result[ResultKey] != nil {
byteBank, err := json.Marshal(result[ResultKey])
if err != nil {
return nil, err
}
bankList := make([]*BankListResult, 0, 0)
if err = json.Unmarshal(byteBank, &bankList); err != nil {
return nil, err
}
return bankList, err
}
return nil, fmt.Errorf("接口[%s],未查询到数据", BankList)
}
// GetMerchantMcc 商户类别查询(获取小类)
func (a *API) GetMerchantMcc(businessScene string, parentCode string) (data []*BusinessResult, err error) {
result := make([]*BusinessResult, 0, 0)
retVal := map[string]interface{}{}
if parentCode != "" { // 获取小类
retVal, err = a.AccessAPI(BaseTestUrl, MerchantMcc, http.MethodGet, parentCode, nil)
if err != nil {
return nil, err
}
} else {
retVal, err = a.AccessAPI(BaseTestUrl, MerchantMcc, http.MethodGet, "", map[string]interface{}{"businessScene": businessScene})
if err != nil {
return nil, err
}
}
if retVal[ResultKey] != nil {
byteBank, err := json.Marshal(retVal[ResultKey])
if err != nil {
return nil, err
}
if err = json.Unmarshal(byteBank, &result); err != nil {
return nil, err
}
return result, err
}
return nil, err
}
// MerchantFeeQuery 商户变更-商户费率查询 customerNo内部商户编号
func (a *API) MerchantFeeQuery(customerNo string, productCode string) (*MerchantFeeResp, error) {
if customerNo == "" {
return nil, fmt.Errorf("customerNo 不能为空")
}
param := map[string]interface{}{}
if productCode != "" {
param["productCode"] = productCode
}
result, err := a.AccessAPI(BaseTestChangeUrl, UpdateFeeQuery, http.MethodGet, customerNo, param)
if err != nil {
return nil, err
}
data := &MerchantFeeResp{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return nil, err
}
return data, err
}
// MerchantFeeChange 商户费率信息变更
func (a *API) MerchantFeeChange(param *FeeChangeReq, customerNo string) (int, string, error) {
if customerNo == "" {
return 0, "", fmt.Errorf("商户ID不能为空")
}
mapParam := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(BaseTestChangeUrl, UpdateFeeQuery, http.MethodPost, customerNo, mapParam)
if err != nil {
return 0, "", err
}
data := &FeeChangeResp{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return 0, "", err
}
if data.StatusCodeValue != utils.Str2Int(BaseSuccess) {
return 0, "", fmt.Errorf(data.StatusCode)
}
return data.Body.ReviewRelatedId, data.Body.Message, nil
}
// UpdateSettleInfo 修改用户结算信息(当param为空时,是查询,不为空时是变更)
func (a *API) UpdateSettleInfo(customerNo string, param *UpdateSettleInfoReq) (*FeeChangeResp, *UpdateSettleInfoReq, error) {
if customerNo == "" {
return nil, nil, fmt.Errorf("商户ID不能为空")
}
mapParam := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(BaseTestChangeUrl, UpdateSettleChange, http.MethodPost, customerNo, mapParam)
if err != nil {
return nil, nil, err
}
if param != nil { // 变更
data := &FeeChangeResp{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return nil, nil, err
}
return data, nil, err
} else { // 查询
data := &UpdateSettleInfoReq{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return nil, nil, err
}
return nil, data, err
}
}
// UpdateBaseInfo 商户基本信息变更
func (a *API) UpdateBaseInfo(customerNo string, changeBaseMap *UpdateBaseInfoReq) (*FeeChangeResp, error) {
if customerNo == "" {
return nil, fmt.Errorf("商户ID不能为空")
}
newMap := utils.Struct2Map(changeBaseMap, "'", false)
base := utils.MergeMaps(newMap, map[string]interface{}{"customerNo": customerNo})
result, err := a.AccessAPI2(BaseTestChangeUrl, UpdateBaseChange, http.MethodPost, "", base)
if err != nil {
return nil, err
}
data := &FeeChangeResp{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return nil, err
}
return data, err
}
// QueryMerchantReviewStatus 查询变更门店审核状态
func (a *API) QueryMerchantReviewStatus(reviewRelatedId string) (string, string, error) {
result, err := a.AccessAPI(BaseTestQueryReviewStatus, QueryChangeReviewStatus, http.MethodGet, "", map[string]interface{}{"reviewRelatedId": reviewRelatedId})
if err != nil {
return "", "", err
}
return result["reviewPass"].(string), result["reviewResult"].(string), err
}
// CheckImgIsSupplement 查看是否补充照片
func (a *API) CheckImgIsSupplement(externalCustomerNo string) (*OpenCustomerExtImgVo, error) {
result, err := a.AccessAPI(BaseTestChangeUrl, CheckImgIsSupplement, http.MethodGet, externalCustomerNo, nil)
if err != nil {
return nil, err
}
imgSupplementResp := &ImgSupplementResp{}
if err = utils.Map2StructByJson(result, imgSupplementResp, false); err != nil {
return nil, err
}
if imgSupplementResp.Code != "200" {
return nil, fmt.Errorf(imgSupplementResp.Message)
}
openCustomerExtImgVo := &OpenCustomerExtImgVo{}
if err = json.Unmarshal([]byte(imgSupplementResp.Data), openCustomerExtImgVo); err != nil {
return nil, err
}
return openCustomerExtImgVo, nil
}
// ImgSupplement 照片补充
func (a *API) ImgSupplement(param *ImgSupplementReq) error {
result, err := a.AccessAPI(BaseTestChangeUrl, ImgIsSupplement, http.MethodPost, "", utils.Struct2Map(param, "", false))
imgSupplementResp := &ImgSupplementResp{}
if err = utils.Map2StructByJson(result, imgSupplementResp, false); err != nil {
return err
}
if imgSupplementResp.Code != "200" {
return fmt.Errorf(imgSupplementResp.Message)
}
return nil
}
// GetMerchantReportStatus 查看银联报备状态
func (a *API) GetMerchantReportStatus(orgCode, agentNo, externalCustomerNo string) (*OpenUnionpayMerchantVo, error) {
param := map[string]interface{}{
"orgCode": orgCode,
"agentNo": agentNo,
"externalCustomerNo": externalCustomerNo,
}
result, err := a.AccessAPI2(BaseTestChangeUrl, ImgIsSupplement, http.MethodPost, "", param)
if err != nil {
return nil, err
}
imgSupplementResp := &ImgSupplementResp{}
if err = utils.Map2StructByJson(result, imgSupplementResp, false); err != nil {
return nil, err
}
if imgSupplementResp.Code != "200" {
return nil, fmt.Errorf(imgSupplementResp.Message)
}
openUnionpayMerchantVo := &OpenUnionpayMerchantVo{}
if err = json.Unmarshal([]byte(imgSupplementResp.Data), openUnionpayMerchantVo); err != nil {
return nil, err
}
return openUnionpayMerchantVo, err
}
// GetMerchantTerminal 获取终端报备信息
func (a *API) GetMerchantTerminal(orgCode, agentNo, externalCustomerNo, posSn string) (*OpenUnionpayTermVo, error) {
param := map[string]interface{}{
"orgCode": orgCode,
"agentNo": agentNo,
"externalCustomerNo": externalCustomerNo,
"posSn": posSn,
}
result, err := a.AccessAPI2(BaseTestChangeUrl, TerminalStatus, http.MethodPost, "", param)
if err != nil {
return nil, err
}
imgSupplementResp := &ImgSupplementResp{}
if err = utils.Map2StructByJson(result, imgSupplementResp, false); err != nil {
return nil, err
}
if imgSupplementResp.Code != "200" {
return nil, fmt.Errorf(imgSupplementResp.Message)
}
openUnionpayTermVo := &OpenUnionpayTermVo{}
if err = json.Unmarshal([]byte(imgSupplementResp.Data), openUnionpayTermVo); err != nil {
return nil, err
}
return openUnionpayTermVo, err
}
// SupplementBusinessLicense 变更营业执照
func (a *API) SupplementBusinessLicense(param *BusinessLicenseReq) (string, string, error) {
req := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(BaseTestChangeUrl, SupplementBusinessLicense, http.MethodPost, "", req)
if err != nil {
return "", "", err
}
data := &FeeChangeResp{}
if err = utils.Map2StructByJson(result, data, false); err != nil {
return "", "", err
}
if data.StatusCodeValue != utils.Str2Int(BaseSuccess) {
return "", "", fmt.Errorf(data.StatusCode)
}
return utils.Int2Str(data.Body.ReviewRelatedId), data.Body.Message, err
}
// UnionPayMerInfo 银联商户信息共享联防机制查询
func (a *API) UnionPayMerInfo(larName, larIdcard string) (*DishonestPerson, error) {
result, err := a.AccessAPI(BaseTestChangeUrl, UnionPayMerInfo, http.MethodPost, "", map[string]interface{}{
"larName": larName,
"larIdcard": larIdcard,
})
if err != nil {
return nil, err
}
person := &DishonestPerson{}
if err = utils.Map2StructByJson(result, person, false); err != nil {
return nil, err
}
return person, nil
}

View File

@@ -0,0 +1,610 @@
package lakala
// 业务访问路由
const (
BaseTestUrl = "https://test.wsmsd.cn/sit/htkregistration" // 测试基础链路
BaseProdUrl = "https://htkactvi.lakala.com/registration" // 正式基础链路
IncomingAction = "merchant" // 进件
OrganizationAction = "organization" // 获取城市code
BankList = "bank" // 银行列表查询
MerchantMcc = "customer/category" // 银行列表查询
FileUpload = "file/upload" // 文件上传
)
// 业务访问路由2
const (
BaseTestChangeUrl = "https://test.wsmsd.cn/sit/htkmerchants" // 测试基础链路
BaseProdChangeUrl = "https://tkapi.lakala.com/htkmerchants" // 正式基础链路
BaseTestQueryReviewStatus = "https://test.wsmsd.cn/sit/htk-api" // 测试查询审核状态路由
BaseProdQueryReviewStatus = "https://htkapi.lakala.com/api" // 正式查询审核状态路由
UpdateFeeQuery = "channel/customer/update/fee" // 商户费率查询-变更
UpdateSettleChange = "channel/customer/update/settle" // 商户结算变更
UpdateBaseChange = "channel/customer/update/basic" // 商户基本信息变更
QueryChangeReviewStatus = "customer/update/review" // 获取商户审核状态
CheckImgIsSupplement = "open/merchant/isUploadPhoto" // 查看当前商户是否补充照片
ImgIsSupplement = "open/merchant/imgSup" // 当前商户补充照片
ReportStatus = "open/merchant/getMerchant" // 银联商户报备状态
TerminalStatus = "open/merchant/getTerm" // 银联终端报备状态
SupplementBusinessLicense = "channel/customer/update/supplement/businessLicense" // 变更营业执照
UnionPayMerInfo = "open/merchant/unionPayMerInfo" // 是否为失信人
GetMerchantInfo = "open/merchant/info" // 获取商户信息
)
const (
IncomingToken = "incoming"
ModifiedToken = "modified"
NotToken = "no"
SignToken = "sign"
ResultKey = "fakeData"
)
// IncomingTokenActive 区分路由使用的token
var IncomingTokenActive = map[string]string{
IncomingAction: IncomingToken,
OrganizationAction: IncomingToken,
MerchantMcc: IncomingToken,
FileUpload: IncomingToken,
TokenActive: NotToken,
UpdateFeeQuery: ModifiedToken,
UpdateSettleChange: ModifiedToken,
UpdateBaseChange: ModifiedToken,
QueryChangeReviewStatus: ModifiedToken,
CheckImgIsSupplement: ModifiedToken,
ImgIsSupplement: ModifiedToken,
ReportStatus: ModifiedToken,
TerminalStatus: ModifiedToken,
SupplementBusinessLicense: ModifiedToken,
UnionPayMerInfo: ModifiedToken,
GetMerchantInfo: IncomingToken,
}
const (
MerchantTypeEnterprise = "TP_MERCHANT" // 企业
MerchantTypePerson = "TP_PERSONAL" // 个人
BankTypeEnterprise = "57" // 对公银行账户
BankTypePerson = "58" // 对私银行账户
)
// 业务类型
const (
Bpos = "BPOS" // 传统POS
Zpos = "ZPOS" // 电签POS
Zpos4G = "ZPOS4G" // 电签POS4G
SuperPos = "SUPER_POS" // 智能pos
BWizard = "B_WIZARD" // 传统语音大POS
PaperCode = "PAPER_CODE" // 码牌
WechartPay = "WECHAT_PAY" // 专业化扫码
ScanningGunPay = "SCANNING_GUN_PAY" // Q码精灵
EasyPayment = "EASY_PAYMENT" // 缴费易
LiantuoEle = "LIANTUO_ELF" // 联拓小精灵
B2BSkm = "B2B_SKM" // B2B收款码
B2Bsyt = "B2B_SYT" // B2B收银台
Klyx = "KLYX" // 云音箱
QrCode = "QRCODE" // 收款王
MoneyBox = "MONEY_BOX" // 收钱宝盒
App = "APP" // APP收款
SuperPosPro = "SUPER_POS_PRO" // 智能PosPro
BusinessCloudPrint = "BUSINESS_CLOUD_PRINT" // 拉生意云打印
YouKeLiLi = "YOU_KE_LI_LI" // 油客里里
LeYouKe = "LE_YOU_KE" // 乐友客
XiaoYiScanCodeOrder = "XIAOYI_SCAN_CODE_ORDER" // 小易扫码点餐
JxCashier = "JX_CASHIER" // 吉祥收银
LKLScrm = "LKL_SCRM" // 拉卡拉SCRM
NakeCashier = "NAKE_CASHIER" // 纳客收银
YinXiangLi = "YIN_XIANG_LI" // 银响力
EasyToPay = "EASY_TO_PAY" // 即易付
UHuoYunOrder = "U_HUO_YUN_ORDER" // 优获云点单
YiXiangRetailV10 = "YIXIANG_RETAIL_V10" // 易享零售V10
AiBaoCashier = "AIBAO_CASHIER" // 爱宝收银
MicroSuperPos = "MICRO_SUPER_POS" // 微智能
HuiYingDoor = "HUI_YING_DOOR" // 慧盈门
ZhiBaiWei = "ZHI_BAI_WEI" // 智百威
YunZhangGui = "YUN_ZHANG_GUI" // 云掌柜
YunchaoTechBc = "YUNCHAO_TECH_BC" // 云超科技线下
PullBusiness = "PULL_BUSINESS" // 拉生意收款宝
WanliNiuRetail = "WANLI_NIU_RETAIL" // 万里牛零售
SmartTourism = "SMART_TOURISM" // 智慧旅游
YiSanCashier = "YI_SAN_CASHIER" // 壹叁收银机
ZhiFu = "ZHI_FU" // 智付
SiXunTianStore = "SI_XUN_TIAN_STORE" // 思迅天店
SmartYouke = "SMART_YOUKE" // 智慧油客
MobilePos = "MOBILE_POS" // 手机POS
HuiButler = "HUI_BUTLER" // 惠管家
ChangYueBao = "CHANG_YUE_BAO" // 场约宝
FourNineEightPost = "FOUR_NINE_EIGHT_POST" // 四九八-邮政
YerSanWu = "YER_SAN_WU" // 惠元付
TianZhiXing = "TIAN_ZHI_XING" // 天之星
TongZhiParking = "TONG_ZHI_PARKING" // 统智停车
TongZhiWuGuan = "TONG_ZHI_WU_GUAN" // 统智物管
YfYm = "YF_YM" // 御风云码
YingCe = "YING_CE" // 鹰策油站
YinBao = "YIN_BAO" // 银豹
Jhpay = "JHPAY" // 聚合支付
YiMaTong = "YI_MA_TONG" // 逸码通
YiMaTongPlus = "YI_MA_TONG_PLUS" // 逸码通PLUS
GaiHuaTengFei = "GAI_HUA_TENG_FEI" // 盖华腾飞
)
// Attchments.Type 附件类型
const (
IdCardFront = "ID_CARD_FRONT" // 身份证正⾯(必传)
IdCardBehind = "ID_CARD_BEHIND" // 身份证反⾯(必传)
BusinessLicence = "BUSINESS_LICENCE" // 营业执照照⽚(企业必传)
BankCard = "BANK_CARD" // 银行卡(对私必传,企业对公传)
AgreeMent = "AGREE_MENT" // 协议(入网协议必传)
OpeningPermit = "OPENING_PERMIT" // 开户许可证(企业对公需要传,对私不传)
CheckstandImg = "CHECKSTAND_IMG" // 收银台照片(必传)
ShopOutsideImg = "SHOP_OUTSIDE_IMG" // 上传门头照片(必传)
ShopInsideImg = "SHOP_INSIDE_IMG" // 商铺内部照片(必传)
Others = "OTHERS" // 其他 无对应类型图片,请传其他类型
SettleIdCardFront = "SETTLE_ID_CARD_FRONT" // 结算人身份证人像面
SettleIdCardBehind = "SETTLE_ID_CARD_BEHIND" // 结算人身份证国徽面
LetterOfAuthorization = "LETTER_OF_AUTHORIZATION" // 法人授权涵
)
// BizContentParam.FeeCode
const (
CreditCard = "CREDIT_CARD" // 贷记卡费率(云闪付必传)
DebitCard = "DEBIT_CARD" // 借记卡费率(云闪付必传,此费率类型必须上送封顶值 topFee
Wechat = "WECHAT" // 微信(必传)
LineWechat = "LINE_WECHAT" // 线上微信(资金类业务不需要传)
Alipay = "ALIPAY" // 支付宝(必传)
UnionpayWalletDebitFee = "UNIONPAY_WALLET_DEBIT_FEE" // 银联二维码借记卡(此费率类型必须上送封顶值 topFee资金类业务同借记卡费率
UnionpayWalletCreditFee = "UNIONPAY_WALLET_CREDIT_FEE" // 银联二维码贷记卡(资金类业务同贷记卡费率)
YSFDiscountDebitFee = "YSF_DISCOUNT_DEBIT_FEE" // 云闪付借记-优惠(资金类业务不需要传)
YSFDiscountCreditFee = "YSF_DISCOUNT_CREDIT_FEE" // 云闪付贷记-优惠(资金类业务不需要传)
YLDiscountDebitFee = "YL_DISCOUNT_DEBIT_FEE" // 银联二维码借记-优惠(资金类业务不需要传)
YLDiscountCreditFee = "YL_DISCOUNT_CREDIT_FEE" // 银联二维码贷记-优惠(资金类业务不需要传)
AlipayDiscountFee = "ALIPAY_DISCOUNT_FEE" // 支付宝优惠费率(资金类业务不需要传)
ScanPaySecond = "SCAN_PAY_SECOND" // 扫码d0费率扫码D0结算必传
CardSecond = "CARD_SECOND" // 刷卡D0费率刷卡D0结算必传
MerWithdrawalSecond = "MER_WITHDRAWAL_SECOND" // 商户秒提费率
YSFLe1000 = "YSF_LE_1000" // 云闪付小额优惠费率(资金类业务不需要传)
)
// MerchantIncomingReq 商户进件
type MerchantIncomingReq struct {
UserNo string `json:"userNo" validate:"required"` // 商户归属用户信息 合作机构信息 由拓客SAAS提供
Email string `json:"email" validate:"required"` // 商户邮箱
BusiCode string `json:"busiCode" validate:"required"` // 根据商务侧业务开放取值,见附录业务类型表
MerRegName string `json:"merRegName" validate:"required"` // 与营业执照名称一致当营业执照名称超过20个字时注册名称可以适当缩减到20字以内
MerType string `json:"merType" validate:"required"` // TP_MERCHANT:企业 TP_PERSONAL:⼩微个⼈
MerName string `json:"merName" validate:"required"` // 商户名称(经营名称)
MerAddr string `json:"merAddr" validate:"required"` // 去掉省,市区后的详细地址
ProvinceCode string `json:"provinceCode" validate:"required"` // 省代码
CityCode string `json:"cityCode" validate:"required"` // 市代码
CountyCode string `json:"countyCode" validate:"required"` // 区县代码
LicenseName string `json:"licenseName"` // 营业执照名称
LicenseNo string `json:"licenseNo"` // 营业执照号码 微商户可不传,其他必传
LicenseDtStart string `json:"licenseDtStart"` // 微商户可不传, 其他必传格式yyyy-MM-dd
LicenseDtEnd string `json:"licenseDtEnd"` // 微商户可不传, 其他必传, 格式yyyy-MM-dd 长期传9999-12-31
Latitude string `json:"latitude" validate:"required"` // 进件所在地址经度
Longtude string `json:"longtude" validate:"required"` // 进件所在地址纬度
Source string `json:"source" validate:"required"` // 进件来源 必传 String 20 进件来源 APP, H5 2选1
BusinessContent string `json:"businessContent" validate:"required"` // 商户经营内容 营业执照上的经营内容20字以内
LarName string `json:"larName" validate:"required"` // 法人姓名
LarIdType string `json:"larIdType" validate:"required"` // 01 身份证 02 护照03 港澳通行证04 台胞证10 外国人永久居留身份证11 港妨澳居民居住证12 台湾居民居住证13 执行事务合伙人99 其它证件
LarIdCard string `json:"larIdCard" validate:"required"` // 法⼈证件号码
LarIdCardStart string `json:"larIdCardStart" validate:"required"` // 证件开始日期格式yyyy-MM-dd
LarIdCardEnd string `json:"larIdCardEnd" validate:"required"` // 证件过期日期 格式yyyy-MM-dd 长期传9999-12-31
ContactMobile string `json:"contactMobile" validate:"required"` // 商户联系⼈⼿机号码
ContactName string `json:"contactName" validate:"required"` // 商户联系⼈姓名
OpenningBankCode string `json:"openningBankCode" validate:"required"` // 结算账户开户⾏号 通过【银行列表查询】接口获取 对应 branchBankNo字段无对应支行可传地区支行
OpenningBankName string `json:"openningBankName" validate:"required"` // 结算账户开户⾏名称
ClearingBankCode string `json:"clearingBankCode" validate:"required"` // 结算账户清算⾏号
SettleProvinceCode string `json:"settleProvinceCode" validate:"required"` // 结算信息省份代码 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
SettleProvinceName string `json:"settleProvinceName" validate:"required"` // 结算信息城市代码 通过【地区信息→获取银行地区查询】接口获取 对应 name字段
SettleCityCode string `json:"settleCityCode" validate:"required"` // 结算信息城市代码
SettleCityName string `json:"settleCityName" validate:"required"` // 结算信息城市名称
AccountNo string `json:"accountNo" validate:"required"` // 结算人银行卡号
AccountName string `json:"accountName" validate:"required"` // 结算人账户名称
AccountType string `json:"accountType" validate:"required"` // 结算账户类型 57 对公 58 对私
AccountIdCard string `json:"accountIdCard" validate:"required"` // 结算⼈证件号码
BizContent BizContentParam `json:"bizContent" validate:"required"` // 业务扩展信息
Attchments []AttchmentsList `json:"attchments" validate:"required"` // 附件信息集合
SettleType string `json:"settleType" validate:"required"` // 结算类型 D0秒到 D1次日结算
//SettlementType string `json:"settlementType" validate:"required"` // 结算方式 MANUAL:手动结算(结算至拉卡拉APP钱包),AUTOMATIC:自动结算到银行卡,REGULAR:定时结算(仅企业商户支持)
AccountIdDtStart string `json:"accountIdDtStart"` // 结算⼈证件开始时间 可选
AccountIdDtEnd string `json:"accountIdDtEnd"` // 结算⼈证件过期时间 可选
}
type BizContentParam struct {
ActivityId string `json:"activityId" validate:"required"` // 归属活动信息 由拓客SAAS分配
Fees []Fees `json:"fees"` // 费率集合
Mcc string `json:"mcc" validate:"required"` // 商户MCC编号
TermNum string `json:"termNum" validate:"required"` // 终端数量
}
type Fees struct {
FeeCode string `json:"feeCode" validate:"required"` // 费率类型
FeeValue string `json:"feeValue" validate:"required"` // 费率值
TopFee string `json:"topFee"` // 封顶值
}
type AttchmentsList struct {
Id string `json:"id" validate:"required"` // ⽂件编号,附件上传接⼝返回的编号(upload接口返回的url字段)
Type string `json:"type" validate:"required"` // 附件类型
}
type MerchantIncomingResp struct {
MerchantNo string `json:"merchant_no"` // 内部商户编号 同拓客其他接口需要使用的customerNo
Status string `json:"status"` // 商户状态 WAIT_AUDI提交成功待审核
}
// MerchantObj 商户集合信息
type MerchantObj struct {
Customer *CustomerObj `json:"customer"` // 商户基础信息 Customer对象 Customer对象
CustomerFee []*CustomerFeeObj `json:"customerFee"` // 商户费率信息 array CustomerFee对象
Pos *PosObj `json:"pos"` // 商户终端信息,绑定才有 Pos Pos
SettleCard *SettleCardObj `json:"settleCard"` // 商户结算信息 CustomerSettleCard对象 CustomerSettleCard对象
TerminalInfo []*TerminalInfoObj `json:"terminalInfo"` // 终端信息集合 array terminalInfo对象
ShopInfoList []*ShopInfoListObj `json:"shopInfoList"` // 网点信息 array ShopInfo对象
ProductVos []*ProductVoObj `json:"productVos"` // 已有产品信息 array CustomerProductVo对象
ExternalNo string `json:"external_no"` // 外部编号 String varchar(32)
}
// CustomerObj 商户基础信息
type CustomerObj struct {
ActiveNo string `json:"activeNo"` // 激活码 string
ActivityTime string `json:"activityTime"` // 激活时间 string(date-time)
AgencyNo int64 `json:"agencyNo"` // 服务商编号 integer(int64)
AgentNo int64 `json:"agentNo"` // 合作方编号 integer(int64)
AgreementStatus string `json:"agreementStatus"` // 协议签署状态 string
BizContent string `json:"bizContent"` // 商户经营范围 string
BzPos string `json:"bzPos"` // POS类型 string
ChannelType string `json:"channelType"` // 商户类型 TP_MERCHANT:企业TP_PERSONAL:小微,可用值:TP_MERCHANT,TP_PERSONAL string
CloseTime string `json:"closeTime"` // 撤机时间 string(date-time)
ContactManName string `json:"contactManName"` // 联系人改名 string
CreateTime string `json:"createTime"` // string(date-time)
CustomerName string `json:"customerName"` // 商户名称 string
CustomerNo int64 `json:"customerNo"` // 商户编号 integer(int64)
CustomerStatus string `json:"customerStatus"` // 商户状态 OPEN:开通CLOSE:关闭LOSS:流失,WAIT_AUDI:审核中,REJECT:审核拒绝,REVIEW_FAIL:复核失败,REVIEW_AUDIT:复核审核中,ACTIVITY:激活 string
AuditRemark string `json:"auditRemark"` // 拒绝原因 商户状态为REJECT返回
ExternalCustomerNo string `json:"externalCustomerNo"` // 外部商户编号 string
IdentityNo string `json:"identityNo"` // 商户身份证号 string
IdentityNoExpire string `json:"identityNoExpire"` // 商户身份证号有效期 string
IsStandard string `json:"isStandard"` // 是否达标 TRUE是 FALSE否 string
LegalName string `json:"legalName"` // 法人姓名 string
LicenseNo string `json:"licenseNo"` // 营业执照号 string
Mailbox string `json:"mailbox"` // 邮箱 string
MccCode string `json:"mccCode"` // 商户类别码 string
MerLicenseExpire string `json:"merLicenseExpire"` // 营业执照号有效期 string
MerName string `json:"merName"` // 企业名称 string
MerchantSource string `json:"merchantSource"` // 商户来源 AGENT:服务商平台APP:APP平台H5:H5平台 string
OpenTime string `json:"openTime"` // 入网时间 string(date-time)
Optimistic int64 `json:"optimistic"` // integer(int32)
PhoneNo string `json:"phoneNo"` // 商户手机号 string
Platform string `json:"platform"` // 平台标识,可用值:LKL string
PosSn string `json:"posSn"` // 机具序列号 string
Position string `json:"position"` // string
RewardMode string `json:"rewardMode"` // 刷够返奖励模式,可用值:TO_MERCHANT,TO_AGENT string
StandardFee float64 `json:"standardFee"` // 提现费等固定费用 number(double)
StandardTime string `json:"standardTime"` // 达标时间 string(date-time)
TermNo string `json:"termNo"` // 虚拟终端号 string
TermNum int32 `json:"termNum"` // 终端数量 integer(int32)
UpdateTime string `json:"updateTime"` // string(date-time)
YsfDiscount string `json:"ysfDiscount"` // 云闪付小额优惠[FALSE:否,TRUE:是] string
ProvinceName string `json:"provinceName"` // 省份名称 string
CityName string `json:"cityName"` // 城市名称 string
CountyName string `json:"countyName"` // 区名称 string
ReceiveDetail string `json:"receiveDetail"` // 详细地址 string
}
// CustomerFeeObj 商户费率信息
type CustomerFeeObj struct {
Id int64 `json:"id"` // integer(int64)
CardType string `json:"cardType"` // 卡类型, 可用值:CREDIT_CARD, QR_CORD, DEBIT_CARD, YSF_LE_1000_CREDIT, YSF_LE_1000_DEBIT string
CreateTime string `json:"createTime"` // string(date-time)
CustomerNo int64 `json:"customerNo"` // 商户编号 integer(int64)
DayLimit float64 `json:"dayLimit"` // 日限额 number(double)
ExternalCustomerNo string `json:"externalCustomerNo"` // string
FeeRate float64 `json:"feeRate"` // 费率 number(double)
MaxAmt float64 `json:"maxAmt"` // 手续费最多值 number(double)
MinAmt float64 `json:"minAmt"` // 手续费最小值 number(double)
MonthLimit float64 `json:"monthLimit"` // 月限额 number(double)
Optimistic int64 `json:"optimistic"` // integer(int32)
PerLimi float64 `json:"perLimi"` // 单笔限额 number(double)
SecondFee float64 `json:"secondFee"` // 秒到手续费 number(double)
TransSettleType string `json:"transSettleType"` // 结算类型, 可用值:D0, D1, T1 string
TransType string `json:"transType"` // 交易类型 string
TremNo string `json:"tremNo"` // 终端号 string 根据transType判断是刷卡还是扫码的终端号信息
UpdateTime string `json:"updateTime"` // string(date-time)
CustomerManagementFee float64 `json:"customerManagementFee"` // 商户管理费费率 number(double)
CustomerManagementdFee float64 `json:"customerManagementdFee"` // 商户管理费d number(double)
CustomerManagementeFee float64 `json:"customerManagementeFee"` // 商户管理费e number(double)
CustomerManagementfFee float64 `json:"customerManagementfFee"` // 商户管理费f number(double)
}
// PosObj 绑定才有
type PosObj struct {
ActiveNo string `json:"activeNo"` // 激活码 string
ActivityFlag string `json:"activityFlag"` // 活动标识 string
OpenTime string `json:"openTime"` // 开通时间 string
PosSn string `json:"posSn"` // 终端序列号 string
PosType string `json:"posType"` // 终端类型 string
TermNo string `json:"termNo"` // 拉卡拉虚拟终端号 string
}
// SettleCardObj 结算信息
type SettleCardObj struct {
AbleStatus string `json:"able_status"` // 可用状态 ,可用值:ENABLE,DISABLE string
AccountKind string `json:"accountKind"` // 账户性质。57对公 58对私 string
AccountName string `json:"accountName"` // 开户名 string
AccountNo string `json:"accountNo"` // 开户账号 string
AuditStatus string `json:"auditStatus"` // 审核状态 string
BankName string `json:"bankName"` // 开户行名称 string
BankNo string `json:"bankNo"` // 开户行编号 string
CityCode string `json:"cityCode"` // 城市编号 string
CityName string `json:"cityName"` // 城市名称 string
ClearingBankNo string `json:"clearingBankNo"` // 清算行号 string
CountyCode string `json:"countyCode"` // 区编号 string
CountyName string `json:"countyName"` // 区名称 string
CreateTime string `json:"createTime"` // string(date-time)
ExternalCustomerNo string `json:"externalCustomerNo"` // string
Id int64 `json:"id"` // integer(int64)
IdCard string `json:"idCard"` // 身份证号 string
Optimistic int64 `json:"optimistic"` // integer(int32)
OwnNo string `json:"ownNo"` // 所有者 string
ProvinceCode string `json:"provinceCode"` // 省份编号 string
ProvinceName string `json:"provinceName"` // 省份名称 string
UpdateTime string `json:"updateTime"` // string(date-time)
Validate string `json:"validate"` // string
}
// ShopInfoListObj 网点信息
type ShopInfoListObj struct {
ShopId int64 `json:"shopId"` // 网点编号 Long
ShopName string `json:"shopName"` // 门店名称 String
ShopAddress string `json:"shopAddress"` // 门店地址 String
ProvinceCode string `json:"provinceCode"` // 省份编号 String
ProvinceName string `json:"provinceName"` // 省份名称 String
CityCode string `json:"cityCode"` // 城市编号 String
CityName string `json:"cityName"` // 城市名称 String
ShopDistCode string `json:"shopDistCode"` // 区编号 String
ShopDistName string `json:"shopDistName"` // 区名称 String
ShopContactName string `json:"shopContactName"` // 联系人 String
ShopContactMobile string `json:"shopContactMobile"` // 联系人手机 String
}
// TerminalInfoObj 终端信息集合
type TerminalInfoObj struct {
CoreTermId int64 `json:"coreTermId"` // 三代终端编号 Long
TermTypeCode int `json:"termTypeCode"` // 终端分类 Integer
TermTypeName string `json:"termTypeName"` // 终端分类名称 string
TermNoList []string `json:"termNoList"` // 终端号 List<String>
ActiveNoVoList []struct {
BusiTypeCode string `json:"busiTypeCode"` // 业务类别码 String
TermNo string `json:"termNo"` // 终端号 String
ActiveNo string `json:"activeNo"` // 终端激活码 String
} `json:"activeNoVoList"` //激活码 List<ActiveNoVo>
}
// ProductVoObj 已有产品信息
type ProductVoObj struct {
Product string `json:"product"` // 商户产品 String
ProductName string `json:"productName"` // 商户产品名称 String
}
// OrganizationList 获取城市组织代码
type OrganizationList struct {
Id int64 `json:"id"`
CreateTime string `json:"createTime"`
Optimistic int64 `json:"optimistic"`
Code string `json:"code"`
Name string `json:"name"`
ParentCode string `json:"parentCode"`
}
// BankListResult 返回的银行列表
type BankListResult struct {
BranchBankNo string `json:"branchBankNo"`
ClearNo string `json:"clearNo"`
BankNo string `json:"bankNo"`
AreaCode string `json:"areaCode"`
BranchBankName string `json:"branchBankName"`
}
// BusinessResult 商户类别查询
type BusinessResult struct {
Code string `json:"code"` // 编码
Name string `json:"name"` //名称
BusinessScene int `json:"businessScene"` //类别的业务场景
CreateTime string `json:"createTime"`
UpdateTime string `json:"updateTime"`
}
// MerchantFeeResp 费率查询
type MerchantFeeResp struct {
Fees []struct {
Discount bool `json:"discount"` // 是否优惠费率
FeeRate string `json:"feeRate"` // 费率
FeeRateMax string `json:"feeRateMax"` // 费率最⼤值
FeeRateMin string `json:"feeRateMin"` // 费率最⼩值
FeeType string `json:"feeType"` // 费率类型
FeeTypeName string `json:"feeTypeName"` // 费率类型名称
FixedValue string `json:"fixedValue"` // 固定值
IsUpper string `json:"isUpper"` // 是否封顶[TRUE是/FALSE不是]
LogicConfig string `json:"logicConfig"` //
MaxAmt string `json:"maxAmt"` // ⼿续费最⼤值
MinAmt string `json:"minAmt"` // ⼿续费最⼩值
RateType string `json:"rateType"` // 费率区间类型 RANG区间 FIXE 定值
RegionValueLogic string `json:"regionValueLogic"` //
TmpMaxAmt string `json:"tmpMaxAmt"` // 模板⼿续费最⼤值
TmpMinAmt string `json:"tmpMinAmt"` // 模板⼿续费最⼩值
Unit string `json:"unit"` // 单位[元/笔 或 %]
} `json:"fees"` // 费率信息列表
SettleType string `json:"settleType"` // 结算周期
SettleTypeList []interface{} `json:"settleTypeList"` // 结算周期可选列表[D0:秒到,D1:D+1到账]
WithdrawalType string `json:"withdrawalType"` // 提款类型
WithdrawalTypeList []struct {
Key string `json:"key"`
Value interface{} `json:"value"`
} `json:"withdrawalTypeList"` // 提款类型[SECOND:秒到;AMOUNT:秒提]
}
// FeeChangeReq 费率变更请求信息
type FeeChangeReq struct {
Attachments []AttachmentDto `json:"attachments"` // 附件信息集合 body false array AttachmentDto
Fees []FeeInfoDto `json:"fees"` // 费率列表 body true array FeeInfoDto
ProductCode string `json:"productCode"` // 产品类型 body true string
SettleType string `json:"settleType"` // 结算⽅式,可⽤值:D0,D1 body false string (D0改D1传终端费率D1改D0传终端费率和D0费率
WithdrawalType string `json:"withdrawalType"` // 提款类型,可用值[SECOND:秒到;AMOUNT:秒提] body false string
SettlementType string `json:"settlementType"` // 结算方式 body false String MANUAL:手动结算,AUTOMATIC:自动结算,REGULAR:定时结算(仅企业商户支持)
RegularSettlementTime string `json:"regularSettlementTime"` // 定时结算时间 body false int 定时结算必传 格式为 HHmm 例如结算时间为下午3点 传入值为 1500
}
// AttachmentDto 附件集合信息
type AttachmentDto struct {
ImgPath string `json:"imgPath"` // 图片路径 通过图片上传接口获取图片地址信息
ImgType string `json:"imgType"`
OpenplatformId string `json:"openplatformId"`
ShowPath string `json:"showPath"`
}
// FeeInfoDto 费率集合信息
type FeeInfoDto struct {
Fee float64 `json:"fee"`
FeeType string `json:"feeType"`
TopFee float64 `json:"top_feel"`
}
// FeeChangeResp 费率变更返回信息
type FeeChangeResp struct {
Body struct {
Message string `json:"message"`
ReviewRelatedId int `json:"reviewRelatedId"` // 变更凭证id[变更结果可通过id进行查询]
} `json:"body"`
StatusCode string `json:"statusCode"`
StatusCodeValue int `json:"statusCodeValue"`
}
// UpdateSettleInfoReq 商户结算信息变更
type UpdateSettleInfoReq struct {
AccountKind string `json:"accountKind"` // 账户性质[57对公 58对私] body false string
AccountName string `json:"accountName"` // 开户名 body false string
AccountNo string `json:"accountNo"` // 银⾏卡号 body false string
Attachments []AttachmentDto `json:"attachments"` // 附件信息集合 body false array AttachmentDto
BankName string `json:"bankName"` // 银⾏名称 body false string 通过【银行列表查询】接口获取 对应 branchBankName字段
BankNo string `json:"bankNo"` // 银⾏编码 body false string 通过【银行列表查询】接口获取 对应 branchBankNo字段
ClearingBankNo string `json:"clearingBankNo"` // ⽀⾏编码 body false string 通过【银行列表查询】接口获取 对应 clearNo字段
IdentityNo string `json:"identityNo"` // 身份证号 body false string
IsLegalPerson bool `json:"isLegalPerson"` // 是否法⼈进件 body false boolean 不传默认法人
ReviewRelatedId int64 `json:"reviewRelatedId"` // 审核关联数据id body false integer(int64)
SettleCityCode string `json:"settleCityCode"` // 结算市代码 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
SettleCityName string `json:"settleCityName"` // 结算市名称 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 name字段
SettleCountyCode string `json:"settleCountyCode"` // 结算区代码 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
SettleCountyName string `json:"settleCountyName"` // 结算区名称 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 name字段
SettleProvinceCode string `json:"settleProvinceCode"` // 结算省份代码 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 code字段
SettleProvinceName string `json:"settleProvinceName"` // 结算省份名称 body false string 通过【地区信息→获取银行地区查询】接口获取 对应 name字段
}
// UpdateBaseInfoReq 商户基本信息变更
type UpdateBaseInfoReq struct {
CustomerNo int64 `json:"customerNo"` // integer(int64) 商户编号
MerBlis string `json:"merBlis"` // 营业执照号
MerBlisName string `json:"merBlisName"` // 营业执照名称
MerBlisExpDt string `json:"merBlisExpDt"` // 营业执照有效期
MerBizName string `json:"merBizName"` // 商户名称
ProvinceCode string `json:"provinceCode"` // 省份编号
ProvinceName string `json:"provinceName"` // 省份名称
CityCode string `json:"cityCode"` // 城市编号
CityName string `json:"cityName"` // 城市名称
CountyCode string `json:"countyCode"` // 区编号
CountyName string `json:"countyName"` // 区名称
MerRegAddr string `json:"merRegAddr"` // 商户详细地址
MerContactName string `json:"merContactName"` // 联系人姓名
MerContactMobile string `json:"merContactMobile"` // 手机号
LarName string `json:"larName"` // 法人姓名
LarIdcard string `json:"larIdcard"` // 证件号码
LarIdcardStDt string `json:"larIdcardStDt"` // 证件开始日期
LarIdcardExpDt string `json:"larIdcardExpDt"` // 证件有效期
FileData []FileDataList `json:"fileData"` // 集合附件数据
ChannelType string `json:"channelType"` // 商户类型 TP_MERCHANT:企业TP_PERSONAL:小微(只有小微变更企业需要传,其它变更不需要传)
MerRegName string `json:"merRegName"` // 注册名称(企业变更注册名称需要传)
}
type FileDataList struct {
ImgPath string `json:"imgPath"` //图片地址 String 否
ImgType string `json:"imgType"` //图片类型 String 否
ShowPath string `json:"showPath"` //showPath String 否
}
// ImgSupplementResp 查看门店是否需要补充照片
type ImgSupplementResp struct {
Code string `json:"code"` // 响应编码
Data string `json:"data"` // OpenCustomerExtImgVo
Message string `json:"message"`
Timestamp int64 `json:"timestamp"`
}
type OpenCustomerExtImgVo struct {
IsUploadPhoto string `json:"isUploadPhoto"` // 照片以补充Y以补充N未补充
IsShopOutside string `json:"isShopOutside"` // 门头照是否已补充Y以补充N未补充
IsShopInside string `json:"isShopInside"` // 內部照是否已补充Y以补充N未补充
}
// ImgSupplementReq 门店补充照片
type ImgSupplementReq struct {
Attachments []struct {
ImgPath string `json:"imgPath"` // 图片地址
ImgType string `json:"imgType"` // 图片类型
OpenplatformId string `json:"openplatformId"` //
ShowPath string `json:"showPath"`
} `json:"attachments"`
ExtCustomerNo string `json:"extCustomerNo"` // 商户号
}
// OpenUnionpayMerchantVo 银联报备,商户报备查询
type OpenUnionpayMerchantVo struct {
AgentNo int `json:"agentNo"` // 机构号
OrgCode string `json:"orgCode"` // 代理商编号
ExternalCustomerNo string `json:"externalCustomerNo"` // 商户编号
CustomerName string `json:"customerName"` // 商户名称
OperationType string `json:"operationType"` // 操作类型I新增U变更D注销R注销
MerStatus string `json:"merStatus"` // 操作类型I新增U变更D注销R注销
Message string `json:"message"` // 报备备注
ReportTime string `json:"reportTime"` // 代理商编号
}
// OpenUnionpayTermVo 终端报备状态查询
type OpenUnionpayTermVo struct {
AgentNo int `json:"agentNo"` // 机构号
OrgCode string `json:"orgCode"` // 代理商编号
ExternalCustomerNo string `json:"externalCustomerNo"` // 商户编号
CustomerName string `json:"customerName"` // 商户名称
OperationType string `json:"operationType"` // 操作类型I新增U变更D注销R注销
MerStatus string `json:"merStatus"` // 操作类型I新增U变更D注销R注销
Message string `json:"message"` // 报备备注
ReportTime string `json:"reportTime"` // 代理商编号
PosSn string `json:"posSn"`
}
// BusinessLicenseReq 变更营业执照
type BusinessLicenseReq struct {
ExternalCustomerNo string `json:"externalCustomerNo"` // 商户编号 必填
MerBlis string `json:"merBlis"` // 营业执照号 必填
MerBlisName string `json:"merBlisName"` // 营业执照名称 必填
MerBlisExpDt string `json:"merBlisExpDt"` // 营业执照有效期 必填
LarName string `json:"larName"` // 法人姓名
LarIdcard string `json:"larIdcard"` // 法人证件号码
LarIdcardExpDt string `json:"larIdcardExpDt"` // 法人证件有效期
FileData []struct {
ImgPath string `json:"imgPath"` // 图片地址
ShowPath string `json:"showPath"` // showPath
ImgType string `json:"imgType"` // 图片类型
} `json:"fileData"`
}
// DishonestPerson 失信人名单
type DishonestPerson struct {
AcqInsNum int `json:"acqInsNum"` // 涉及收单机构数量
CloseMchntNum int `json:"closeMchntNum"` // 共共计查询到的退出记录数量
IsInBlackList string `json:"isInBlackList"` // 是否黑名单
SignMchntNum int `json:"signMchntNum"` // 共共计查询到的商户记录数量
}

View File

@@ -0,0 +1,152 @@
package lakala
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"time"
)
// CreateOrder 创建交易订单
func (a *API) CreateOrder(param *CreateOrderReq) (*CreateOrderResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version2,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(OrderTestUrl, CrateOrderActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != Success {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &CreateOrderResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// CloseOrder 订单关单(超时支付订单,主动关闭)
func (a *API) CloseOrder(param *CloseOrderReq) (string, error) {
if param.OutOrderNo == "" && param.PayOrderNo == "" {
return "", fmt.Errorf("out_order_no,pay_order_no 不能同时为空")
}
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version2,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(OrderTestUrl, CloseOrderActive, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
if result["code"].(string) != Success {
return "", fmt.Errorf(result["msg"].(string))
}
return result["resp_data"].(map[string]string)["order_status"], err
}
// QueryOrder 收银订单查询
func (a *API) QueryOrder(outOrderNo string, merchantNo string) (*QueryOrderResp, error) {
reqParameter := map[string]interface{}{
"req_data": map[string]string{"out_order_no": outOrderNo, "merchant_no": merchantNo, "channel_id": "15"},
"version": Version2,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(OrderTestUrl, QueryOrderActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != Success {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &QueryOrderResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// RefundOrder 订单统一退货
func (a *API) RefundOrder(param *RefundOrderReq) (*RefundOrderResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version2,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(OrderTestUrl, OrderRefundActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != Success {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &RefundOrderResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// RefundOrderQuery 订单同一退货查询
func (a *API) RefundOrderQuery(param *RefundOrderQueryReq) ([]*RefundOrderQueryResp, error) {
if param.OriginOutTradeNo == "" && param.OriginTradeRefNo == "" {
return nil, fmt.Errorf("退款流水号/系统参考号必传一个")
}
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version2,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(OrderTestUrl, OrderRefundQueryActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != Success {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"].(map[string]interface{})["refund_list"])
if err != nil {
return nil, err
}
resp := make([]*RefundOrderQueryResp, 0, 0)
if err = json.Unmarshal(bodyResult, &resp); err != nil {
return nil, err
}
return resp, nil
}

View File

@@ -0,0 +1,223 @@
package lakala
const (
OrderTestUrl = "https://test.wsmsd.cn/sit/api/v3/" // 收银订单创建测试地址
OrderProdUrl = "https://s2.lakala.com/api/v3" // 收银订单创建正式地址
CrateOrderActive = "ccss/counter/order/special_create" // 创建订单
CloseOrderActive = "ccss/counter/order/close" // 订单关单
QueryOrderActive = "ccss/counter/order/query" // 订单查询
OrderRefundActive = "lams/trade/trade_refund" // 订单统一退货
OrderRefundQueryActive = "lams/trade/trade_refund_query" // 订单统一退货查询
)
const (
OrderCloseStatusWaitPay = "0"
OrderCloseStatusPaying = "1"
OrderCloseStatusPaySuccess = "2"
OrderCloseStatusPayFail = "3"
OrderCloseStatusExpire = "4"
OrderCloseStatusCancel = "5"
OrderCloseStatusRefund = "6"
OrderCloseStatusClose = "7"
)
// CreateOrderReq 拉卡拉创建支付订单
type CreateOrderReq struct {
OutOrderNo string `json:"out_order_no"` // M String 32 商户订单号 12345678
MerchantNo string `json:"merchant_no"` // M String 32 银联商户号 822100041120005
TotalAmount int64 `json:"total_amount"` // M long 12 订单金额,单位:分 200
OrderEfficientTime string `json:"order_efficient_time"` // M String 14 订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+7天 20210803141700
OrderInfo string `json:"order_info"` // M String 64 订单标题,在使用收银台扫码支付时必输入,交易时送往账户端
VposId string `json:"vpos_id"` // C String 32 交易设备标识进件返回接口中的termId字段非API接口进件请联系业务员。 462621830268882944
ChannelId string `json:"channel_id"` // C String 32 渠道号 (一般不用) 24865454154
NotifyUrl string `json:"notify_url"` // C String 128 订单支付成功后商户接收订单通知的地址 http://xxx.xxx.com
SupportCancel int `json:"support_cancel"` // C int 1 是否支持撤销 默认 0 不支持 busi_mode为“PAY-付款”不支持 撤销 0 不支持 1支持
SupportRefund int `json:"support_refund"` // C int 1 是否支持退款 默认0 不支持 0 不支持 1支持
SupportRepeatPay int `json:"support_repeat_pay"` // C int 1 是否支持“多次发起支付” 默认0 不支持 0 不支持 1支持
OutUserId string `json:"out_user_id"` // C String 64 发起订单方的userId归属于channelId下的userId
CallbackUrl string `json:"callback_url"` // C String 128 客户端下单完成支付后返回的商户网页跳转地址。
TermNo string `json:"term_no"` // C String 32 结算终端号,合单场景必输该字段
SplitMark string `json:"split_mark"` // C String 2 合单标识“1”为合单不填默认是为非合单
SettleType string `json:"settle_type"` // C String 4 结算类型(非合单) “0”或者空常规结算方式 注意该字段会影响结算方式慎用。调用拉卡拉分账接口需必传1
OutSplitInfo []OutSplitInfoObj `json:"out_split_info"` // C List<> 拆单信息合单标识为“1”时必传该字段。,详细字段见out_split_info字段说明
CounterParam string `json:"counter_param"` // C String 1024 json字符串 收银台展示参数 {\“pay_mode\“ : \“ALIPAY\“} ,指定支付方式为支付宝 ALIPAY支付宝 WECHAT微信 UNION银联云闪付 CARDPOS刷卡交易 LKLAT线上转帐 QUICK_PAY快捷支付 EBANK网银支付 UNION_CC银联支付 BESTPAY翼支付 HB_FQ花呗分期 UNION_FQ银联聚分期 ONLINE_CARDLESS线上外卡若要指定支付方式为支付宝传参格式{\“pay_mode\“ : \“ALIPAY\“}
CounterRemark string `json:"counter_remark"` // C String 128 收银台备注
BusiTypeParam string `json:"busi_type_param"` // C String 256 业务类型控制参数jsonStr格式 [{\“busi_type\“:\“UPCARD\“,\“params\“:{\“crd_flg\“:\“CRDFLG_D|CRDFLG_C|CRDFLG_OTH\“}},{\“busi_type\“:\“SCPAY\“,\“params\“:{\“pay_mode\“:\“ALIPAY\“,\“crd_flg\“:\“CRDFLG_D\“}}] 说明UPCARD-刷卡SCPAY-扫码CRDFLG_D-借记卡CRDFLG_C-贷记卡CRDFLG_OTH-不明确是借记卡还是贷记卡pay_mode送参说明ALIPAY-支付宝WECHAT-微信UNION-银联二维码DCPAY-数字货币BESTPAY-翼支付说明一旦使用该字段则增加限制必须在指定限制范围内支付。比如只配置”busi_type”:”UPCARD”的参数而不配置”busi_type”:”SCPAY”的参数则只能通过刷卡而不能通过扫码完成支付
SgnInfo []string `json:"sgn_info"` // C list<> 签约协议号列表(字符串) [“1234”,”2345”],不支持空列表[];列表中签约协议号不能为空;列表中签约协议号不能重复
ProductId string `json:"product_id"` // C String 6 指定产品编号 200809:线上外卡收银台) 注意:该字段默认不需要指定,特殊场景下使用,慎用
GoodsMark string `json:"goods_mark"` // C String 商品信息标识 1:含商品信息,不填默认不含商品信息)
GoodsField string `json:"goods_field"` // C String 2 商品信息域(good_mark送1时该域必填否则不送。只有线上外卡业务上送该字段) 详细字段见goods_field字段说明
OrderSceneField *OrderSceneFieldObj `json:"order_scene_field"` // C Object 2 订单场景域,特殊场景下需要上送 详细字段见order_scene_field字段说明
AgeLimit string `json:"age_limit"` // C String 1 0:不限年龄1:年龄限制
RepeatPayAutoRefund string `json:"repeat_pay_auto_refund"` // C String 1 0:重复支付后不自动退货1:重复支付后自动退货 默认不送为0注意请详细了解字段场景后上送 需注意互斥条件repeat_pay_auto_refund选择“1”重复支付后自动退货后repeat_pay_notify仅支持选择“0”重复支付订单不通知
RepeatPayNotify string `json:"repeat_pay_notify"` // C String 1 0:重复支付订单不通知1:重复支付订单通知 默认不送为0
CloseOrderAutoRefund string `json:"close_order_auto_refund"` // C String 1 0:不自动退货1:关闭订单后支付成功触发自动退货 默认不送为0注意请详细了解字段场景后上送
ShopName string `json:"shop_name"` // C String 64 网点名称
InteRouting string `json:"inte_routing"` // C String 2 智能路由下单标识 1-是 0-否默认不送为0备注需要在收银台管控台配置聚合收银台小程序白名单
DiscountCode string `json:"discount_code"` // C String 64 优惠码(目前供线上国补下单使用)
}
type OutSplitInfoObj struct {
OutSubOrderNo string `json:"out_sub_order_no"` // 外部子订单号 M String(32) 商户子订单号
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的银联商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
Amount string `json:"amount"` // 金额 M String(12) 单位分,整数型字符
SettleType string `json:"settle_type"` // 结算类型(合单) C String(4) “0”或者空常规结算方式
}
type OrderSceneFieldObj struct {
OrderSceneType string `json:"order_scene_type"` // 订单场景类型 M String(16) 订单场景类型按下述定义场景送值HB_FQ花呗分期场景KL_FQ考拉分期场景
SceneInfo string `json:"scene_info"` // 订单场景信息 C String(1024) 订单场景信息json字符串格式不同的订单场景类型需要上送的结构不一样详见具体场景
}
// CreateOrderResp 创建订单返回参数
type CreateOrderResp struct {
MerchantNo string `json:"merchant_no"`
ChannelId string `json:"channel_id"`
OutOrderNo string `json:"out_order_no"`
OrderCreateTime string `json:"order_create_time"`
OrderEfficientTime string `json:"order_efficient_time"`
PayOrderNo string `json:"pay_order_no"`
CounterUrl string `json:"counter_url"`
}
// CloseOrderReq 订单关单参数, 要么传out_order_no要么传pay_order_no
type CloseOrderReq struct {
MerchantNo string `json:"merchant_no"` // M String 32 商户号 822100041120005
OutOrderNo string `json:"out_order_no"` // C String 32 商户订单号 12345678
PayOrderNo string `json:"pay_order_no"` // C String 64 支付订单号 21070211012001970631000383039
ChannelId string `json:"channel_id"` // C String 32 渠道号 10
}
// QueryOrderResp 查询订单详情
type QueryOrderResp struct {
PayOrderNo string `json:"pay_order_no"` // M String 64 支付订单号 21070211012001970631000383039
OutOrderNo string `json:"out_order_no"` // M String 32 商户订单号 12345678
ChannelId string `json:"channel_id"` // M String 32 渠道号
TransMerchantNo string `json:"trans_merchant_no"` // C String 32 交易商户号
TransTermNo string `json:"trans_term_no"` // C String 16 交易终端号
MerchantNo string `json:"merchant_no"` // M String 32 结算商户号(合单订单中该结算商户号为主单名义上结算商户号) 822126090640003
TermNo string `json:"term_no"` // M String 16 结算终端号(合单订单中该结算商户号为主单名义上结算终端号)
OrderStatus string `json:"order_status"` // M String 2 订单状态 0:待支付 1:支付中 2:支付成功 3:支付失败 4:已过期 5:已取消 6:部分退款或者全部退款 7:订单已关闭枚举
OrderInfo string `json:"order_info"` // C String 100 订单描述
TotalAmount int64 `json:"total_amount"` // M long 12 订单金额,单位:分 200
OrderCreateTime string `json:"order_create_time"` // M String 14 订单创建时间 格式yyyyMMddHHmmss
OrderEfficientTime string `json:"order_efficient_time"` // M String 14 订单有效时间 格式yyyyMMddHHmmss
SettleType string `json:"settle_type"` // C String 4 结算类型(非合单) “0”或者空常规结算方式
SplitMark string `json:"split_mark"` // C String 2 合单标识 “1”为合单不填默认是为非拆单
CounterParam string `json:"counter_param"` // C String 1024 json字符串 收银台参数 {\“pay_mode\“ : \“ALIPAY\“} ,指定支付方式为支付宝
CounterRemark string `json:"counter_remark"` // C String 128 收银台备注
BusiTypeParam string `json:"busi_type_param"` // C String 256 业务类型控制参数jsonStr格式 [{\“busi_type\“:\“UPCARD\“,\“params\“:{\“crd_flg\“:\“CRDFLG_D|CRDFLG_C|CRDFLG_OTH\“}},{\“busi_type\“:\“SCPAY\“,\“params\“:{\“crd_flg\“:\“CRDFLG_D\“}}]说明UPCARD-刷卡SCPAY-扫码CRDFLG_D-借记卡CRDFLG_C-贷记卡CRDFLG_OTH-不明确是借记卡还是贷记卡说明一旦使用该字段则增加限制必须在指定限制范围内支付。比如只配置”busi_type”:”UPCARD”的参数而不配置”busi_type”:”SCPAY”的参数则只能通过刷卡而不能通过扫码完成支付
OutSplitInfo []OutSplitInfoObj `json:"out_split_info"` // C List<>商户拆单信息, 详细字段见out_split_info字段说明
SplitInfo []SplitInfoObj `json:"split_info"` // C List<交易拆单信息 详细字段见split_info字段说明
SgnInfo []string `json:"sgn_info"` // C list<>签约协议号列表 [“1234”,”2345”]
GoodsMark string `json:"goods_mark"` // C String 2 商品标识
GoodsField string `json:"goods_field"` // C String 2048 商品信息
OrderTradeInfoList []OrderTradeInfoListObj `json:"order_trade_info_list"` // M List<>订单交易信息列表 list单元为ObjectObject对象包含如下字段 ,按交易完成时间逆序排列
}
type SplitInfoObj struct {
SubTradeNo string `json:"sub_trade_no"` // 子单交易流水号 M String(32) 子单交易流水号
SubLogNo string `json:"sub_log_no"` // 子单对账单流水号 M String(14) 子单对账单流水号
OutSubOrderNo string `json:"out_sub_order_no"` // 外部子订单号 M String(32) 商户子订单号
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的银联商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
Amount string `json:"amount"` // 金额 M String(12) 单位分,整数型字符
}
type OrderTradeInfoListObj struct {
TradeNo string `json:"trade_no"` // M String 32 交易流水号 2021070266210002570007或者 21080302570007
LogNo string `json:"log_no"` // M String 14 对账单流水号 66210002570007或者 21080302570007
TradeRefNo string `json:"trade_ref_no"` // M String 12 交易参考号 080302570007,仅busi_type为UPCARD时返回
TradeType string `json:"trade_type"` // M String 16 交易类型 PAY-消费 REFUND-退款 CANCEL-撤销
TradeStatus string `json:"trade_status"` // M String 2 支付状态 返回状态 S:成功 F:失败 C:被冲正 U:预记状态 X:发送失败 T: 发送超时 P: 处理中
TradeAmount int64 `json:"trade_amount"` // M long 12 交易金额,单位:分 200
PayerAmount int64 `json:"payer_amount"` // M long 12 付款人实际支付金额,单位:分
UserId1 string `json:"user_id1"` // C String 64 用户标识1 微信sub_open_id 支付宝buyer_logon_id买家支付宝账号
UserId2 string `json:"user_id2"` // C String 64 用户标识2 微信openId 支付宝buyer_user_id 银联user_id
BusiType string `json:"busi_type"` // M String 16 支付业务类型UPCARD-银行卡SCPAY-扫码支付DCPAY-数币支付ONLINE-线上支付
TradeTime string `json:"trade_time"` // C String 14 交易完时间 格式yyyyMMddHHmmss
AccTradeNo string `json:"acc_trade_no"` // C String 32 付款受理交易流水号 支付宝流水号、微信流水号
PayerAccountNo string `json:"payer_account_no"` // C String 32 付款人账号
PayerName string `json:"payer_name"` // C String 32 付款人名称仅ONLINE交易返回
PayerAccountBank string `json:"payer_account_bank"` // C String 32 付款账号开户行
AccType string `json:"acc_type"` // C String 2 账户类型 busi_type为UPCARD时返回00-借记卡,01-贷记卡,02-准贷记卡,03-预付卡busi_type为SCPAY时返回00不确定,02-微信零钱,03-支付宝花呗,04-支付宝钱包,99-未知
PayMode string `json:"pay_mode"` // C String 2 付款方式 busi_type为SCPAY时返回UQRCODEPAY-银联、WECHAT-微信、ALIPAY-支付宝
ClientBatchNo string `json:"client_batch_no"` // C String 6 终端批次号 刷卡交易终端批次号只有busi_type为UPCARD时返回
ClientSeqNo string `json:"client_seq_no"` // C String 6 终端流水号 刷卡交易终端流水号只有busi_type为UPCARD时返回
SettleMerchantNo string `json:"settle_merchant_no"` // C String 32 结算商户号
SettleTermNo string `json:"settle_term_no"` // C String 16 结算终端号
OriginTradeNo string `json:"origin_trade_no"` // C String 32 原交易流水号(扫码交易的退款场景中,对应原交易流水号) 2021070266210002570007
AuthCode string `json:"auth_code"` // C String 64 快捷签约协议号
BankType string `json:"bank_type"` // C String 64 付款银行
ResultDescstring string `json:"result_descstring"` // (待上线) C String 32 交易结果描述
}
// RefundOrderReq 统一退单请求接口
type RefundOrderReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 是 String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 是 String(32) 拉卡拉分配的终端号
OutTradeNo string `json:"out_trade_no"` // 商户请求流水号 是 String(32) 商户系统唯一
RefundAmount string `json:"refund_amount"` // 退款金额 是 String(12) 单位分,整数数字型字符
OriginBizType string `json:"origin_biz_type"` // 原业务类型 是 String(1) 原交易类型:1 银行卡2 外卡3 扫码4 线上
OriginTradeDate string `json:"origin_trade_date"` // 原交易日期 是 String(8) 原交易日期yyyyMMdd
OriginLogNo string `json:"origin_log_no"` // 拉卡拉对账单流水号 否 String(14) 正交易返回的拉卡拉对账单流水号
OriginTradeNo string `json:"origin_trade_no"` // 原交易拉卡拉交易订单号 否 String(32) 下单成功时返回的扫码系统生成的送往账户方的交易流水号在微信或支付宝交易信息界面显示为商户订单号origin_log_no和origin_trade_no任填其一
OriginCardNo string `json:"origin_card_no"` // 原交易银行卡号 否 String(32) 原交易银行卡号银行卡退款必填如无完整卡号可送交易通知时的脱敏卡号如6226****8223
LocationInfo *LocationInfo `json:"location_info"` // 地址位置信息 否 Object 地址位置信息
RefundType string `json:"refund_type"` // 退款模式 否 String(2) 当商户进件时退货模式配置的为 指定模式退货时该字段有效。00退货帐户, 05商户余额退货, 06终端余额退货
}
// LocationInfo 地址信息
type LocationInfo struct {
RequestIp string `json:"request_ip"` // 请求方IP地址 M String(64) 请求方的IP地址存在必填格式如36.45.36.95
BaseStation string `json:"base_station"` // 基站信息 C String(128) 客户端设备的基站信息(主扫时基站信息使用该字段)
Location string `json:"location"` // 维度, 经度 C String(32) 商户终端的地理位置,存在必填 格式:纬度, 经度,+表示北纬、东经,-表示南纬、 西经精度最长支持小数点后9位。举例:+37.123456789, -121.123456789
}
// RefundOrderResp 统一退单响应
type RefundOrderResp struct {
LogNo string `json:"log_no"` // 拉卡拉退款单号
TradeTime string `json:"trade_time"` // 平台交易时间
OutTradeNo string `json:"out_trade_no"` // out_trade_no
TotalAmount string `json:"total_amount"` // 交易金额
PayerAmount string `json:"payer_amount"` // 实际退款金额
RefundAmount string `json:"refund_amount"` // 申请退款金额
AccTradeNo interface{} `json:"acc_trade_no"` // 账户端交易订单号
OriginLogNo interface{} `json:"origin_log_no"` // 原拉卡拉统一交易单号
OriginTradeNo string `json:"origin_trade_no"` // 原交易拉卡拉交易订单号
OriginOutTradeNo string `json:"origin_out_trade_no"` // 原商户请求流水号
}
// RefundOrderQueryReq 统一退货查询
type RefundOrderQueryReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 是 String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 是 String(32) 拉卡拉分配的终端号
OutTradeNo string `json:"out_trade_no"` // 商户请求流水号 是 String(64) 商户系统唯一
OriginTradeDate string `json:"origin_trade_date"` // 原交易日期 是 String(8) 原退货交易日期yyyyMMdd 20200326posp接口必填
OriginBizType string `json:"origin_biz_type"` // 原业务类型 是 String(1) 原交易类型:1 银行卡2 外卡3 扫码4 线上
OriginTradeNo string `json:"origin_trade_no"` // 原交易拉卡拉交易订单号 否 String(32) 小票订单号、微信/支付宝商家订单号
OriginTradeRefNo string `json:"origin_trade_ref_no"` // 系统参考号 否 String(12) 小票参考号
OriginOutTradeNo string `json:"origin_out_trade_no"` // 退款请求流水号 否 String(32) 原退款交易商户请求流水号
}
// RefundOrderQueryResp 统一退货查询
type RefundOrderQueryResp struct {
OutTradeNo string `json:"out_trade_no"` // 商户请求流水号
TradeTime string `json:"trade_time"` // 交易时间
TradeState string `json:"trade_state"` // 交易状态
TradeNo string `json:"trade_no"` // 拉卡拉商户订单号
LogNo string `json:"log_no"` // 拉卡拉退款单号
RefundAmount string `json:"refund_amount"` // 交易金额
PayMode interface{} `json:"pay_mode"` // 支付方式
CrdNo interface{} `json:"crd_no"` // 卡号
AccountType string `json:"account_type"` // 钱包类型
OpenId string `json:"open_id"` // 用户标识
SubOpenId string `json:"sub_open_id"` // 用户子标识
BankType interface{} `json:"bank_type"` // 付款银行
PayerAmount string `json:"payer_amount"` // 付款人实付金额
AccSettleAmount string `json:"acc_settle_amount"` // 账户端结算金额
AccMdiscountAmount string `json:"acc_mdiscount_amount"` // 商户侧优惠金额(账户端)
AccDiscountAmount string `json:"acc_discount_amount"` // 账户端优惠金额
}

View File

@@ -0,0 +1,80 @@
package lakala
import (
"fmt"
"testing"
)
func TestCreateOrder(t *testing.T) {
api.CreateOrder(&CreateOrderReq{
OutOrderNo: "KFPT20220714160009228907288",
MerchantNo: "8222900701106PZ",
TotalAmount: 1,
OrderEfficientTime: "20220714170009",
OrderInfo: "",
VposId: "587305941625155584",
ChannelId: "2021052614391",
NotifyUrl: "http://run.mocky.io/v3/b02c9448-20a2-4ff6-a678-38ecab30161d",
SupportCancel: 0,
SupportRefund: 1,
SupportRepeatPay: 1,
OutUserId: "",
CallbackUrl: "",
TermNo: "",
SplitMark: "",
SettleType: "",
OutSplitInfo: nil,
CounterParam: "",
CounterRemark: "",
BusiTypeParam: "",
SgnInfo: nil,
ProductId: "",
GoodsMark: "",
GoodsField: "",
OrderSceneField: nil,
AgeLimit: "",
RepeatPayAutoRefund: "",
RepeatPayNotify: "",
CloseOrderAutoRefund: "",
ShopName: "",
InteRouting: "",
DiscountCode: "",
})
}
func TestCloseOrder(t *testing.T) {
api.CloseOrder(&CloseOrderReq{
MerchantNo: "8222900701105HK",
OutOrderNo: "KFPT2022071415575938951152",
PayOrderNo: "",
ChannelId: "",
})
}
func TestQueryOrder(t *testing.T) {
api.QueryOrder("21092211012001970631000488042", "822290059430BFA")
}
func TestRefundOrderQuery(t *testing.T) {
api.RefundOrderQuery(&RefundOrderQueryReq{
MerchantNo: "8222900701105HK",
TermNo: "A0073841",
OutTradeNo: "54F73F36356D4E4E83A86FD8658BEB51",
OriginTradeDate: "20210930",
OriginBizType: "3",
OriginTradeNo: "2021093066210003980394",
OriginTradeRefNo: "",
OriginOutTradeNo: "",
})
}
func Test1111(t *testing.T) {
aa := []int{2, 4, 6, 8, 10, 12, 14}
sum := 0
for _, v := range aa {
if v%2 == 0 {
sum += v
}
}
fmt.Println(sum)
}

View File

@@ -0,0 +1,127 @@
package lakala
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"time"
)
// AggregatePay 主扫聚合支付(小程序支付)
func (a *API) AggregatePay(param *AggregatePayReq) (*AggregatePayResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version3,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(PayTestUrl, PayActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != PaySuccess {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &AggregatePayResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// AggregateRefund 主扫退款 (已经对接了一个了)
func (a *API) AggregateRefund(param *AggregateRefundReq) (*AggregateRefundResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version3,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(PayTestUrl, RefundActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != PaySuccess {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &AggregateRefundResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// PayStatusQuery 支付查询
func (a *API) PayStatusQuery(param *PayStatusQueryReq) (*PayStatusQueryResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version3,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(PayTestUrl, PayQueryActive, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != PaySuccess {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &PayStatusQueryResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// ScannerPayMicroPay 扫码枪扫码支付
func (a *API) ScannerPayMicroPay(param *PayMicroPayReq) (string, string, string, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version3,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(PayTestUrl, PayMicropayActive, http.MethodPost, "", reqParameter)
if err != nil {
return "", "", "", err
}
switch result["code"].(string) {
case PaySuccess, "BBS10000", "BBS11105":
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return "", "", "", err
}
resp := &PayMicroPayResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", "", "", err
}
return result["code"].(string), result["msg"].(string), resp.TradeNo, nil
default:
return "", "", "", fmt.Errorf(result["msg"].(string))
}
}

View File

@@ -0,0 +1,286 @@
package lakala
const (
PayTestUrl = "https://test.wsmsd.cn/sit/api/v3/" // 收银订单创建测试地址
PayProdUrl = "https://s2.lakala.com/api/v3" // 收银订单创建正式地址
PayActive = "labs/trans/preorder" // 主扫聚合
PayMicropayActive = "labs/trans/micropay" // 聚合被扫
RefundActive = "labs/relation/refund" // 主扫退款
PayQueryActive = "labs/query/tradequery" // 支付查询
)
const (
PayStatusINIT = "INIT" // 初始化
PayStatusCREATE = "CREATE" // 下单成功
PayStatusSUCCESS = "SUCCESS" // 交易成功
PayStatusFAIL = "FAIL" // 交易失败
PayStatusDEAL = "DEAL" // 交易处理中
PayStatusUNKNOWN = "UNKNOWN" // 未知状态
PayStatusCLOSE = "CLOSE" // 订单关闭
PayStatusPARTREFUND = "PART_REFUND" // 部分退款
PayStatusREFUND = "REFUND" // 全部退款
PayStatusREVOKED = "REVOKED" // 订单撤销
)
// AggregatePayReq 聚合主扫参数
type AggregatePayReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 M String(32) 商户系统唯一,对应数据库表中外部请求流水号。
AccountType string `json:"account_type"` // 钱包类型 M String(32) 微信WECHAT 支付宝ALIPAY 银联UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 拉卡拉支付账户LKLACC 网联小钱包NUCSPAY 京东钱包JD
TransType string `json:"trans_type"` // 接入方式 M String(2) 41:NATIVEALIPAY云闪付支持京东白条分期51:JSAPI微信公众号支付支付宝服务窗支付银联JS支付翼支付JS支付, 拉卡拉钱包支付, 支付宝小程序支付71:微信小程序支付61:APP支付微信APP支付
TotalAmount string `json:"total_amount"` // 金额 M String(12) 单位分,整数型字符
LocationInfo LocationInfoObj `json:"location_info"` // 地址位置信息 M Object 地址位置信息,风控要求必送
BusiMode string `json:"busi_mode"` // 业务模式 C String(8) 业务模式: ACQ-收单 不填默认为“ACQ-收单”
Subject string `json:"subject"` // 订单标题 C String(42) 标题,用于简单描述订单或商品主题,会传递给账户端 账户端控制实际最多42个字符微信支付必送。
PayOrderNo string `json:"pay_order_no"` // 支付业务订单号 C String(64) 拉卡拉订单系统订单号,以拉卡拉支付业务订单号为驱动的支付行为,需上传该字段。
NotifyUrl string `json:"notify_url"` // 商户通知地址 C String(128) 商户通知地址,如果上传,且 pay_order_no 不存在情况下,则按此地址通知商户(详见“[交易通知]”接口)
SettleType string `json:"settle_type"` // 结算类型 C String(4) “0”或者空常规结算方式如需接拉卡拉分账通需传“1”商户未开通分账之前切记不用上送此参数。
Remark string `json:"remark"` // 备注 C String(128)
PnrInsIdCd string `json:"pnr_ins_id_cd"` // 服务商机构标识码 C String(11) 银联分配的服务商机构标识码
AccBusiFields interface{} `json:"acc_busi_fields"` // 账户端业务信息域 (微信小程序支付-71、公众号支付-51 必传) C Object 参见以下acc_busi_fields字段详细说明,不同的account_type和trans_type需要传入的参数不一样
CompleteNotifyUrl string `json:"complete_notify_url"` // 发货确认通知地址 C String(128) 发货类小程序确认收获后通知商户的地址
}
type LocationInfoObj struct {
RequestIp string `json:"request_ip"` // 请求方IP地址 M String(64) 请求方的IP地址存在必填格式如36.45.36.95
BaseStation string `json:"base_station"` // 基站信息 C String(128) 客户端设备的基站信息(主扫时基站信息使用该字段)
Location string `json:"location"` // 纬度, 经度 C String(32)商户终端的地理位置,银联二维码交易必填,整体格式:纬度, 经度,+表示北纬、东经,-表示南纬、 西经。经度格式1位正负号+3位整数+1位小数点+5位小数纬度格式1位正负号+2位整数+1位小数点+6位小数举例+31.221345, +121.12345
}
// AccBusiFieldsByWeChat acc_busi_fields 只有微信小程序和公众号支付时需要此参数
type AccBusiFieldsByWeChat struct {
TimeoutExpress string `json:"timeout_express"` // 预下单有效时间 C String(2) 预下单的订单的有效时间以分钟为单位。建议不超过15分钟。不传值则默认5分钟。(微信主扫下单上送的失效时间是控制prepay_id调起支付的有效时间。微信后台不会根据失效时间发起关单。 如需关单,调用关单接口。)
SubAppid string `json:"sub_appid"` // 子商户公众账号ID C String(32) 微信分配的子商户公众账号IDsub_appid即微信小程序支付-71、公众号支付-51、微信app支付-61此参数必传只对微信支付有效 工行数字钱包情况下该字段上送工行的openId 拉卡拉钱包情况下该字段上送LAKALA的userId
UserId string `json:"user_id"` // 用户标识 C String(64) 用户在子商户sub_appid下的唯一标识sub_openid即微信小程序支付-71、众号支付-51此参数必传只对微信支付有效
Detail string `json:"detail"` // 商品详情 WeChatDetail C String(1024) 单品优惠功能字段,详见下文说明
GoodsTag string `json:"goods_tag"` // 订单优惠标记 C String(32) 订单优惠标记微信平台配置的商品标记用于优惠券或者满减使用accountType为WECHAT时可选填此字段
Attach string `json:"attach"` // 附加域 C String(128) 该字段主要用于商户携带订单的自定义数据。商户定制字段,直接送到账户端。
DeviceInfo string `json:"device_info"` // 设备号 C String(32) 终端设备号(门店号或收银设备ID)注意PC网页或JSAPI支付请传”WEB”
LimitPay string `json:"limit_pay"` // 指定支付方式 C String(20) no_credit指定不能使用信用卡支付
SceneInfo string `json:"scene_info"` // 场景信息 C String(256) 该字段用于上报场景信息,目前支持上报实际门店信息。
LimitPayer string `json:"limit_payer"` // 限定支付 C String(8) ADULT成年人
}
// WeChatDetail 微信支付商品详情
type WeChatDetail struct {
CostPrice string `json:"cost_price"` // C String(12) 1.商户侧一张小票订单可能被分多次支付,订单原 价用于记录整张小票的交易金额。 2.当订单原价与支付金额不相等,则不享受优惠。 3.该字段主要用于防止同一张小票分多次支付,以 享受多次优惠的情况,正常支付订单不必上传此参 数。 如608800
ReceiptId string `json:"receipt_id"` // C String(12) 商家小票 ID
GoodsDetail []WeChatGoodsDetail `json:"goods_detail"` // M Object 单品信息使用Json数组格式提交见示例
}
type WeChatGoodsDetail struct {
GoodsId string `json:"goods_id"` // M String(32) 由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。如“商品编码”
WxpayGoodsId string `json:"wxpay_goods_id"` // C String(32) 微信支付定义的统一商品编号
GoodsName string `json:"goods_name"` // C String(256) 商品的实际名称
Quantity int `json:"quantity"` // M int 用户购买的数量
PriceM int `json:"price_m"` // 单位为:分。如果商户有优惠,需传输商户优惠后的单价
}
// AccBusiFieldsByAliPay acc_busi_fields 支付宝支付
type AccBusiFieldsByAliPay struct {
UserId string `json:"user_id"` // 用户标识 C String(64) 用户在子商户sub_appid下的唯一标识sub_openid即微信小程序支付-71、众号支付-51此参数必传只对微信支付有效
TimeoutExpress string `json:"timeout_express"` // 预下单有效时间 C String(2) 预下单的订单的有效时间以分钟为单位。建议不超过15分钟。不传值则默认5分钟。(微信主扫下单上送的失效时间是控制prepay_id调起支付的有效时间。微信后台不会根据失效时间发起关单。 如需关单,调用关单接口。)
ExtendParams interface{} `json:"extend_params"` // 支付宝业务扩展参数 ,见说明
GoodsDetail interface{} `json:"goods_detail"`
StoreId string `json:"store_id"`
DisablePayChannels string `json:"disable_pay_channels"`
BusinessParams string `json:"business_params"`
MinAge string `json:"min_age"`
PromoParams interface{} `json:"promo_params"`
PriorityPayAssets interface{} `json:"priority_pay_assets"`
}
// AggregatePayResp 请求支付响应报文
type AggregatePayResp struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号(请求接口中商户号)
OutTradeNo string `json:"out_trade_no"` // 商户请求流水号 M String(32) 请求报文中的商户请求流水号
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号 M String(32) 拉卡拉交易流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号 M String(14) 拉卡拉对账单流水号
SettleMerchantNo string `json:"settle_merchant_no"` // 结算商户号 M String(32) 拉卡拉分配的商户号
SettleTermNo string `json:"settle_term_no"` // 结算终端号 M String(32) 拉卡拉分配的业务终端号
AccRespFields interface{} `json:"acc_resp_fields"` // 账户端返回信息域 C Object 账户端返回信息域
}
// AccRespFieldsAliNative 阿里_NATIVE 支付返回
type AccRespFieldsAliNative struct {
Code string `json:"code"` // 二维码信息 M String(256) 商户可用此参数自定义去生成二维码后展示出来进行扫码支付
CodeImage string `json:"code_image"` // 二维码图片内容 M String(256) 商户收款二维码图片。Base64编码暂无
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
}
// AccRespFieldsAliJSAPI 阿里_JSAPI
type AccRespFieldsAliJSAPI struct {
PrepayId string `json:"prepay_id"` // 预下单Id M String(32) 预支付交易会话ID
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
}
// AccRespFieldsWechatJSAPIAndMin 微信(71-小程序)微信(51-JSAPI)场景下
type AccRespFieldsWechatJSAPIAndMin struct {
PrepayId string `json:"prepay_id"` // 预下单Id M String(32) 预支付交易会话ID
PaySign string `json:"pay_sign"` // 支付签名信息 M String(256) 签名
AppId string `json:"app_id"` // 小程序id M String(32) 商户注册具有支付权限的小程序成功后即可获得小程序id
TimeStamp string `json:"time_stamp"` // 时间戳 M String(32) 当前的时间
NonceStr string `json:"nonce_str"` // 随机字符串 M String(32) 随机字符串
Package string `json:"package"` // 订单详情扩展字符串 M String(128)
SignType string `json:"sign_type"` // 签名方式 M String(32) 签名类型支持RSA
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
}
// AccRespFieldsUQRCodeAndJdPay 银联京东41-NATIVE 支付返回
type AccRespFieldsUQRCodeAndJdPay struct {
Code string `json:"code"` // 二维码信息 M String(256) 商户可用此参数自定义去生成二维码后展示出来进行扫码支付
}
// AccRespFieldsUQRCodeJsApi 银联JSAPI支付
type AccRespFieldsUQRCodeJsApi struct {
RedirectUrl string `json:"redirect_url"` // 银联JS支付重定向地址 M String(256) 银联JS支付返回重定向地址
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
}
// AccRespFieldsBestPayJsApi 银联JSAPI支付
type AccRespFieldsBestPayJsApi struct {
BestPayInfo string `json:"best_pay_info"` // 翼支付JS参数 C String(512) 翼支付JS参数(老网联) best_pay_info、redirect_url两者有其一
RedirectUrl string `json:"redirect_url"` // 翼支付支付重定向地址 C String(256) 翼支付支付重定向地址(新网联)
}
// AccRespFieldsWechatApp 微信app支付
type AccRespFieldsWechatApp struct {
PrepayId string `json:"prepay_id"` // 预下单Id M String(32) 预支付交易会话ID
PaySign string `json:"pay_sign"` // 支付签名信息 M String(256) 签名
AppId string `json:"app_id"` // 移动应用appid M String(32) 商户注册具有支付权限的安卓/IOSAPP成功后即可获得移动应用appid
TimeStamp string `json:"time_stamp"` // 时间戳 M String(32) 当前的时间
NonceStr string `json:"nonce_str"` // 随机字符串 M String(32) 随机字符串
Package string `json:"package"` // 订单详情扩展字符串 M String(128)
SignType string `json:"sign_type"` // 签名方式 M String(32) 签名类型支持RSA
PartnerId string `json:"partner_id"` // 从业机构号 M String(32)
SubMchId string `json:"sub_mch_id"` // 子商户号 C String(20) 账户端子商户号
}
// AggregateRefundReq 主扫退款参数
type AggregateRefundReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 M String(32) 商户系统唯一,对应数据库表中外部请求流水号。
RefundAmount string `json:"refund_amount"` // 退款金额 M String(12) 单位分,整数数字型字符
RefundReason string `json:"refund_reason"` // 退款原因 C String(32) 退款原因描述
OriginOutTradeNo string `json:"origin_out_trade_no"` // 原商户请求流水号
OriginTradeNo string `json:"origin_trade_no"` // 原拉卡拉交易流水号 C String(32) 下单成功时,返回的拉卡拉交易流水。 origin_out_trade_no、origin_log_no、origin_trade_no至少一个必填调用收银台下单接口拉起交易后发起退款时至少要传两个同时存在时优先级顺序如下 origin_trade_no、origin_log_no、origin_out_trade_no。
OriginLogNo string `json:"origin_log_no"` // 原对账单流水号 C String(14) 对账单中的交易流水。 origin_out_trade_no、origin_log_no、origin_trade_no至少一个必填调用收银台下单接口拉起交易后发起退款时至少要传两个同时存在时优先级顺序如下 origin_trade_no、origin_log_no、origin_out_trade_no。
LocationInfo LocationInfoObj `json:"location_info"` // 地址位置信息 M Object 地址位置信息,风控要求必送
}
// AggregateRefundResp 主扫退款响应参数
type AggregateRefundResp struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
OutTradeNo string `json:"out_trade_no"` // 请求中的商户请求流水号
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号
AccTradeNo string `json:"acc_trade_no"` // 账户端交易流水号
AccountType string `json:"account_type"` // 微信WECHAT 支付宝ALIPAY 银联UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING
TotalAmount string `json:"total_amount"` // 单位分,整数数字型字符串
RefundAmount string `json:"refund_amount"` // 单位分,整数数字型字符串
PayerAmount string `json:"payer_amount"` // 单位分,整数数字型字符串
TradeTime string `json:"trade_time"` // 实际退款时间。yyyyMMddHHmmss
OriginTradeNo string `json:"origin_trade_no"` // 如果请求中携带,则返回
OriginOutTradeNo string `json:"origin_out_trade_no"` // 如果请求中携带,则返回
UpIssAddnData string `json:"up_iss_addn_data"` // 参与单品营销优惠时返回
UpCouponInfo string `json:"up_coupon_info"` // 参与单品营销优惠时返回
TradeInfo string `json:"trade_info"` // 数字货币中行返回示例说明:[{“fundchannel”:”BOC”,”amount”:”18”}]
}
// PayStatusQueryReq 支付查询
type PayStatusQueryReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的终端号
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 C String(32) 下单时的商户请求流水号 说明out_trade_no、trade_no、必有其一。如果存在多个字段上送优先级顺序如下 trade_no、 out_trade_no
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号 C String(32) 拉卡拉交易流水号
}
type PayStatusQueryResp struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号(交易请求接口中商户号)
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 M String(64)
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号 M String(32) 拉卡拉交易流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号 M String(14) trade_no的后14位
TradeMainType string `json:"trade_main_type"` //交易大类 C String(32) PREORDER-主扫MICROPAY-被扫REFUND-退款CANCEL-撤销,无-其它类型
SplitAttr string `json:"split_attr"` // 拆单属性 C String(1) 只有涉及合单交易时会出现M-主单S-子单
SplitInfo []SplitInfoList `json:"split_info"` //拆单信息 C List<> 如果查询订单是主单则返回。见splitInfo字段说明。拆单信息见split_info域说明
TradeState string `json:"trade_state"` // 交易状态 M String(16) INIT-初始化 CREATE-下单成功 SUCCESS-交易成功 FAIL-交易失败 DEAL-交易处理中 UNKNOWN-未知状态 CLOSE-订单关闭 PART_REFUND-部分退款 REFUND-全部退款(或订单被撤销)
TradeStateDesc string `json:"trade_state_desc"` // 交易状态描述 C String(256) 交易状态描述
AccTradeNo string `json:"acc_trade_no"` // 账户端交易订单号 M String(32) 账户端交易订单号
AccountType string `json:"account_type"` // 钱包类型 M String(32) 微信WECHAT 支付宝ALIPAY 银联UQRCODEPAY 翼支付: BESTPAY 苏宁易付宝: SUNING 数字人民币-DCPAY
TotalAmount string `json:"total_amount"` // 订单金额 M String(12) 单位分,整数数字型字符
PayerAmount string `json:"payer_amount"` // 付款人实付金额 C String(12) 付款人实付金额,单位分
AccSettleAmount string `json:"acc_settle_amount"` // 账户端结算金额 C String(12) 账户端应结订单金额,单位分 ,账户端应结订单金额=付款人实际发生金额+账户端优惠金额
AccMdiscountAmount string `json:"acc_mdiscount_amount"` // 商户侧优惠金额(账户端) C String(12) 商户优惠金额,单位分
AccDiscountAmount string `json:"acc_discount_amount"` // 账户端优惠金额 C String(12) 账户端优惠金额,单位分
AccOtherDiscountAmount string `json:"acc_other_discount_amount"` // 账户端其它优惠金额 C String(12) 账户端返回账户端其它优惠金额,单位分
TradeTime string `json:"trade_time"` // 交易完成时间 C String(14) 实际支付时间。yyyyMMddHHmmss
UserId1 string `json:"user_id1"` // 用户标识1 C String(128) 微信sub_open_id, 支付宝buyer_logon_id买家支付宝账号
UserId2 string `json:"user_id2"` // 用户标识2 C String(128) 微信openId,支付宝buyer_user_id,银联user_id
BankType string `json:"bank_type"` // 付款银行 C String(128) 付款银行
CardType string `json:"card_type"` // 银行卡类型 C String(16) 00借记 01贷记 02微信零钱 03支付宝花呗 04支付宝其他 05数字货币 06拉卡拉支付账户 99未知 sha
AccActivityId string `json:"acc_activity_id"` // 活动 ID C String(32) 在账户端商户后台配置的批次 ID
TradeReqDate string `json:"trade_req_date"` // 交易请求日期 M String(8)
AccRespFields interface{} `json:"acc_resp_fields"` // 账户端返回信息域 C Object 账户端返回信息域
RefundSplitInfo []RefundSplitInfoObj `json:"refund_split_info"` // 合单退款拆单信息 C List<> 如果查询订单是退款主单则返回。见refundSplitInfo字段说明。拆单信息见refund_split_info域说明
}
type SplitInfoList struct {
UbTradeNo string `json:"ub_trade_no"` // 子单交易流水号 M String(32) 子单交易流水号
SubLogNo string `json:"sub_log_no"` // 子单对账单流水号 M String(14) 子单对账单流水号
OutSubTradeNo string `json:"out_sub_trade_no"` // 外部子交易流水号 M String(32) 商户子交易流水号,商户号下唯一
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
MerchantName string `json:"merchant_name"` // 商户名称 M String(64) 商户名称
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
Amount string `json:"amount"` // 金额 M String(12) 单位分,整数型字符
}
type RefundSplitInfoObj struct {
OutSubTradeNo string `json:"out_sub_trade_no"` // 外部子退款交易流水号 M String(32) 商户子交易流水号,商户号下唯一
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
RefundAmount string `json:"refund_amount"` // 申请退款金额 M String(12) 单位分,整数型字符
SubTradeNo string `json:"sub_trade_no"` // 拉卡拉子交易流水号 C String(32)
SubLogNo string `json:"sub_log_no"` // 对账单子流水号 C String(14) sub_trade_no后14位
TradeState string `json:"trade_state"` // 子交易状态 C String(16) SUCCESS-交易成功 FAIL-交易失败
ResultCode string `json:"result_code"` // 处理结果码 C String(32)
ResultMsg string `json:"result_msg"` // 处理描述 C String(128)
}
// PayMicroPayReq 扫码支付
type PayMicroPayReq struct {
MerchantNo string `json:"merchant_no"` // 商户号 M String(32) 拉卡拉分配的商户号
TermNo string `json:"term_no"` // 终端号 M String(32) 拉卡拉分配的业务终端号
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号 M String(32) 商户系统唯一,对应数据库表中外部请求流水号。
AuthCode string `json:"auth_code"` // M String(32) 扫码支付授权码设备读取用户APP中的条码或者二维码信息用户付款码条形码规则见说明
TotalAmount string `json:"total_amount"` // 单位分,整数型字符
LocationInfo LocationInfoObj `json:"location_info"` // 地址位置信息 M Object 地址位置信息,风控要求必送
NotifyUrl string `json:"notify_url"` // 商户通知地址,如上传,且 pay_order_no 不存在情况下,且支付响应报文是交易中状态的场景下,则按此地址通知商户
SettleType string `json:"settle_type"` // “0”或者空常规结算方式如需接拉卡拉分账通需传“1”商户未开通分账之前切记不用上送此参数。
Subject string `json:"subject"` // 标题用于简单描述订单或商品账户端控制实际最多42个字符微信支付必送。
//busi_mode string `json:"busi_mode"` // 业务模式: ACQ-收单 不填默认为“ACQ-收单”
//pay_order_no string `json:"pay_order_no"` // 拉卡拉订单系统订单号,以拉卡拉支付业务订单号为驱动的支付行为,需上传该字段。 订单交易下单,交易时上送订单系统订单号,交易流程中会校验有效性、判重
//remark string `json:"remark"`
//scan_type string `json:"scan_type"`
//acc_busi_fields interface{} `json:"acc_busi_fields"`
//pnr_ins_id_cd string `json:"pnr_ins_id_cd"`
}
type PayMicroPayResp struct {
NeedQuery string `json:"need_query"` // 是否需要发起查询 0=不需要 1=需要 当返回1时代表订单处理中商户需主动发起查询
OutTradeNo string `json:"out_trade_no"` // 商户交易流水号
TradeNo string `json:"trade_no"` // 拉卡拉交易流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号
AccTradeNo string `json:"acc_trade_no"` // 账户端交易流水号
AccountType string `json:"account_type"` // 微信WECHAT 支付宝ALIPAY 银联UQRCODEPAY 翼支付: BESTPAY 数字货币DCPAY
TotalAmount string `json:"total_amount"` // 单位分,整数数字型字符 订单金额=付款人实际发生金额+商户优惠金额+账户端优惠金额
PayerAmount string `json:"payer_amount"` // 付款人实际发生金额
AccSettleAmount string `json:"acc_settle_amount"` // 应结订单金额,单位分 ,账户端应结订单金额=付款人实际发生金额+账户端优惠金额
AccMdiscountAmount string `json:"acc_mdiscount_amount"` // 账户端返回商户优惠金额,单位分
AccDiscountAmount string `json:"acc_discount_amount"` // 账户端返回账户端优惠金额,单位分
TradeTime string `json:"trade_time"` // 以账户端返回时间为准
BankType string `json:"bank_type"` // 付款银行
CardType string `json:"card_type"` // 00借记 01贷记 02微信零钱 03支付宝花呗 04支付宝其他 05数字货币 06拉卡拉支付账户 99未知
}

View File

@@ -0,0 +1,66 @@
package lakala
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"git.rosy.net.cn/jx-callback/globals"
"testing"
)
func TestSign(t *testing.T) {
api.signParamRSA(nil, LaKaLaPublicKey)
}
func TestJiami(t *testing.T) {
sign, err := signParamRSA2("8000000000001", "1610334026688401311", "1621690412", "123456789012", LaKaLaPrivateKey)
globals.SugarLogger.Debugf("---sign := %s", sign)
globals.SugarLogger.Debugf("---err := %v", err)
}
// signParamRSA 支付签名
func signParamRSA2(appId, serialNo, timeStamp, nonceStr, RSAPrivate string) (sign string, err error) {
block, _ := pem.Decode([]byte(RSAPrivate))
private, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// 签名参数
body1, err := json.Marshal(`{"reqData":....此处省略具体报文......}`)
sm4Key, _ := base64.StdEncoding.DecodeString(SM4Key)
body2, err := SM4ECBEncrypt(body1, sm4Key)
if err != nil {
return "", err
}
bodyData := base64.StdEncoding.EncodeToString(body2)
context := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", appId, serialNo, timeStamp, nonceStr, bodyData)
// 进行rsa加密签名
hashed := sha256.Sum256([]byte(context))
signedData, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey), crypto.SHA256, hashed[:])
if err != nil {
return "", err
}
signData := base64.StdEncoding.EncodeToString(signedData)
authorization := signData // fmt.Sprintf(`LKLAPI-SHA256withRSA appid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"`, a.appID, a.serialNo, timeStamp, nonceStr, signData)
return authorization, nil
}
func TestPayStatusQuery(t *testing.T) {
api.PayStatusQuery(&PayStatusQueryReq{
MerchantNo: "822290059430BFA",
TermNo: "29034705",
OutTradeNo: "FD660E1FAA3A4470933CDEDAE1EC1D8E",
TradeNo: "",
})
}

View File

@@ -0,0 +1,426 @@
package lakala
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"time"
)
// CreateSeparate 进件成功的门店创建分账
func (a *API) CreateSeparate(param *CreateSeparateReq) (string, error) {
if (param.SplitLaunchMode == SplitLaunchModeAuto || param.SplitLaunchMode == SplitLaunchModePointRule) && param.SplitRuleSource == "" {
return "", fmt.Errorf("当分账发起方式为%s/%s时,分账规则来源不能为空", SplitLaunchModeAuto, SplitLaunchModePointRule)
}
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": param.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateAccountApplyAction, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", err
}
resp := &CreateSeparateResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", err
}
if resp.RetCode != Success {
return "", fmt.Errorf(resp.RetMsg)
}
return utils.Int64ToStr(resp.RespData.ApplyId), nil
}
// SeparateModify 商户申请变更分账商户
func (a *API) SeparateModify(modify *SeparateModifyReq) (string, error) {
if modify.MerInnerNo == "" && modify.MerCupNo == "" {
return "", fmt.Errorf("k卡拉卡内部账号或银联账号不能同时为空")
}
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(modify, "", false),
"reqId": modify.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateAccountModifyAction, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", err
}
resp := &CreateSeparateResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", err
}
if resp.RetCode != Success {
return "", fmt.Errorf(resp.RetMsg)
}
return utils.Int64ToStr(resp.RespData.ApplyId), nil
}
// SeparateQuery 商户分账信息查询
func (a *API) SeparateQuery(query *SeparateQueryReq) (*SeparateQueryResp, error) {
if query.MerInnerNo == "" && query.MerCupNo == "" {
return nil, fmt.Errorf("卡卡拉卡内部账号或银联账号不能同时为空")
}
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(query, "", false),
"reqId": query.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateAccountQueryAction, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["retCode"].(string) != Success {
return nil, fmt.Errorf(result["retMsg"].(string))
}
bodyResult, err := json.Marshal(result["respData"])
if err != nil {
return nil, err
}
resp := &SeparateQueryResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// CreateSeparateRecipient 创建分账接收方
func (a *API) CreateSeparateRecipient(recipient *CreateSeparateRecipientReq) (string, error) {
switch recipient.AcctTypeCode {
case BankTypeEnterprise:
if recipient.AcctNo == "" {
return "", fmt.Errorf("收款账户账户类型为对公,必须上送[营业执照编号]")
}
if recipient.LicenseName == "" {
return "", fmt.Errorf("收款账户账户类型为对公,必须上送[营业执照名称]")
}
if recipient.LegalPersonName == "" {
return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人姓名]")
}
if recipient.LegalPersonCertificateType == "" {
return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人证件类型]")
}
if recipient.LegalPersonCertificateNo == "" {
return "", fmt.Errorf("收款账户账户类型为对公,必须上送[法人证件号]")
}
default:
}
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(recipient, "", false),
"reqId": recipient.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateReceiverApplyAction, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", err
}
resp := &CreateSeparateRecipientResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", err
}
if resp.RetCode != Success {
return "", fmt.Errorf(resp.RetMsg)
}
return resp.RespData.ReceiverNo, nil
}
// UpdateSeparateRecipient 分账接收方变更申请
func (a *API) UpdateSeparateRecipient(param *UpdateSeparateRecipientReq) (string, error) {
if param.ReceiverNo == "" {
return "", fmt.Errorf("分账接收方编号不能为空")
}
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": param.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateReceiverModifyAction, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", err
}
resp := &CreateSeparateRecipientResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", err
}
if resp.RetCode != Success {
return "", fmt.Errorf(resp.RetMsg)
}
return resp.RespData.OrderNo, nil
}
// QuerySeparateRecipient 分账方详细信息查询
func (a *API) QuerySeparateRecipient(orderNo, receiverNo string) (*QuerySeparateRecipientResp, error) {
reqParameter := map[string]interface{}{
"reqData": map[string]string{
"version": Version,
"orderNo": orderNo,
"orgCode": a.orgCode,
"receiverNo": receiverNo,
},
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateReceiverQueryAction, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return nil, err
}
resp := &QuerySeparateRecipientResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, nil
}
// ApplyBind 申请绑定分账关系
func (a *API) ApplyBind(param *SeparateApplyBindReq) (*SeparateApplyBindResp, error) {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": param.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateBindAction, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return nil, err
}
resp := &SeparateApplyBindResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
if resp.RetCode != Success {
return nil, fmt.Errorf(resp.RetMsg)
}
return resp, nil
}
// SeparateUnBind 申请解除绑定
func (a *API) SeparateUnBind(param *SeparateUnBindReq) (string, error) {
reqParameter := map[string]interface{}{
"reqData": utils.Struct2Map(param, "", false),
"reqId": param.OrderNo,
"version": Version,
"reqTime": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateAccountTestUrl, SeparateUnBindAction, http.MethodPost, "", reqParameter)
if err != nil {
return "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", err
}
resp := &SeparateApplyBindResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", err
}
if resp.RetCode != Success {
return "", fmt.Errorf(resp.RetMsg)
}
return utils.Int64ToStr(resp.RespData.ApplyId), nil
}
// Separate 分账
func (a *API) Separate(param *OrderSeparateReq) (string, string, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateTest, SeparateOrder, http.MethodPost, "", reqParameter)
if err != nil {
return "", "", err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return "", "", err
}
resp := &OrderSeparateResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return "", "", err
}
if resp.Code != SeparateSuccess {
return "", "", fmt.Errorf(resp.Msg)
}
return resp.RespData.Status, resp.RespData.SeparateNo, nil
}
// SeparateCancel 订单分账撤销
func (a *API) SeparateCancel(param *SeparateCancelReq) (*SeparateCancelResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateTest, SeparateCancel, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return nil, err
}
resp := &SeparateCancelResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
if resp.Code != SeparateSuccess {
return nil, fmt.Errorf(resp.Msg)
}
return resp, err
}
// SeparateFallBack 分账退回
func (a *API) SeparateFallBack(param *SeparateFallReq) (*SeparateFallResp, error) {
reqParameter := map[string]interface{}{
"req_data": utils.Struct2Map(param, "", false),
"version": Version,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateTest, SeparateFallBack, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
bodyResult, err := json.Marshal(result)
if err != nil {
return nil, err
}
resp := &SeparateFallResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
if resp.Code != SeparateSuccess {
return nil, fmt.Errorf(resp.Msg)
}
return resp, err
}
// SeparateResultQuery 分账结果查询
func (a *API) SeparateResultQuery(merchantNo, separateNo string) (*SeparateResultQueryResp, error) {
reqData := map[string]string{
"merchant_no": merchantNo,
"separate_no": separateNo,
}
reqParameter := map[string]interface{}{
"req_data": reqData,
"version": Version,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateTest, SeparateQuery, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != SeparateSuccess {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &SeparateResultQueryResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, err
}
// SeparateQueryAmt 可分账金额查询
func (a *API) SeparateQueryAmt(merchantNo, logNo, logDate string) (*SeparateQueryAmtResp, error) {
reqData := map[string]string{
"merchant_no": merchantNo,
"log_no": logNo,
"log_date": logDate,
}
reqParameter := map[string]interface{}{
"req_data": reqData,
"version": Version,
"req_time": utils.Time2TimeStrByFormat(time.Now(), TimeFormat),
}
result, err := a.AccessAPISign(SeparateTest, SeparateQueryAmt, http.MethodPost, "", reqParameter)
if err != nil {
return nil, err
}
if result["code"].(string) != SeparateSuccess {
return nil, fmt.Errorf(result["msg"].(string))
}
bodyResult, err := json.Marshal(result["resp_data"])
if err != nil {
return nil, err
}
resp := &SeparateQueryAmtResp{}
if err = json.Unmarshal(bodyResult, resp); err != nil {
return nil, err
}
return resp, err
}

View File

@@ -0,0 +1,417 @@
package lakala
const (
TimeFormat = "20060102150405"
Success = "000000"
SeparateSuccess = "SACS0000"
BaseSuccess = "200"
PaySuccess = "BBS00000"
Version = "1.0.0"
Version2 = "v1.0.0"
Version3 = "3.0"
SplitLaunchModeAuto = "AUTO" // 自动规则分账
SplitLaunchModePointRule = "POINTRULE" // 指定规则分账
)
// 分账前置
const (
SeparateAccountTestUrl = "https://test.wsmsd.cn/sit/api/v2/mms/openApi/ledger" // 测试
SeparateAccountProdUrl = "https://s2.lakala.com/api/v2/mms/openApi/ledger" // 生产
SeparateAccountApplyAction = "applyLedgerMer" // 商户申请开通分账
SeparateAccountModifyAction = "modifyLedgerMer" // 商户变更申请开通分账
SeparateAccountQueryAction = "queryLedgerMer" // 商户分账信息查询
SeparateReceiverApplyAction = "applyLedgerReceiver" // 分账接受方创建
SeparateReceiverModifyAction = "modifyLedgerReceiver" // 分账接受方变更
SeparateReceiverQueryAction = "queryReceiverDetail" // 分账接受方查询
SeparateBindAction = "applyBind" // 分账关系绑定
SeparateUnBindAction = "applyUnBind" // 分账关系解除绑定
)
// 分账
const (
SeparateTest = "https://test.wsmsd.cn/sit/api/v3/sacs" // 测试环境分账
SeparateProd = "https://s2.lakala.com/api/v3/sacs" // 正式环境分账
SeparateOrder = "separate" // 订单分账
SeparateCancel = "cancel" // 分账撤销 分账撤销支持30日内全额撤销撤销金额回到商户分账账户撤销后可再次发起分账。多用于分账错误需撤销后重新分账场景
SeparateFallBack = "fallback" // 分账退回 180天内退货退款
SeparateQuery = "query" // 分账结果查询
SeparateQueryAmt = "queryAmt" // 可分账金额查询
)
const (
FrIdFront = "FR_ID_CARD_FRONT" // 法人身份证正面
FrIdBehind = "FR_ID_CARD_BEHIND" // 法人身份证反面
IdFront = "ID_CARD_FRONT" // 身份证正面
IdBehind = "ID_CARD_BEHIND" // 身份证反面
BankCard2 = "BANK_CARD" // 银行卡
BusinessLicence2 = "BUSINESS_LICENCE" // 营业执照
MerchantPhoto = "MERCHANT_PHOTO" // 商户门头照
ShopInner = "SHOPINNER" // 商铺内部照片
NetWorkXy = "NETWORK_XY" // 电子协议
SplitEntrustFile = "SPLIT_ENTRUST_FILE" // 分账结算授权委托书
SplitCooperationFile = "SPLIT_COOPERATION_FILE" // 分账合作协议
OTHERS // 其他
)
// CreateSeparateReq 商户创建分账
type CreateSeparateReq struct {
Version string `json:"version"` //必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` //必传 String 32 订单编号(便于后续跟踪排查问题及回调消息匹配) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` //必传 String 32 机构代码
MerInnerNo string `json:"merInnerNo"` //可选 String 32 拉卡拉内部商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
MerCupNo string `json:"merCupNo"` //可选 String 32 银联商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
ContactMobile string `json:"contactMobile"` //必传 String 32 联系手机号
SplitLowestRatio float64 `json:"splitLowestRatio"` //必传 数字 32 最低分账比例百分比支持2位精度 70 或 70.50
SplitEntrustFileName string `json:"splitEntrustFileName"` //必传 String 64 分账结算委托书文件名称 分账结算委托书文件名称.pdf
SplitEntrustFilePath string `json:"splitEntrustFilePath"` //必传 String 64 分账结算委托书文件路径 调用商户入网接口上传附件后反馈的文件路径: 文件上传
RetUrl string `json:"retUrl"` //必传 String 128 回调通知地址 请确保可以直接访问,避免接收不到我方通知结果,如果无法接收处理,也可以自行通过 3.商户分账信息查询接口 确定开通结果(注意分账业务申请需人工审核,存在一定延时)
SplitRuleSource string `json:"splitRuleSource"` //条件必传 String 32 分账规则来源 MER商户分账规则PLATFORM平台分账规则分账发起方式为自动规则或指定规则时必传
SplitRange string `json:"splitRange"` //非必传 String 32 分账范围 ALL全部交易分账 (商户所有交易默认待分账) MARK标记交易分账(只有带分账标识交易待分账,其余交易正常结算) 默认MARK
SepFundSource string `json:"sepFundSource"` //非必传 String 32 分账依据 TR交易分账BA余额分账默认TR 交易分账
EleContractNo string `json:"eleContractNo"` //非必传 String 32 电子合同编号 如果已经签署过电子合同此处上送电子合同编号即可,供审核人员复核使用。
SplitLaunchMode string `json:"splitLaunchMode"` //非必传 String 32 分账发起方式 AUTO自动规则分账POINTRULE指定规则分账MANUAL 手动分账不填默认MANUAL
SettleType string `json:"settleType"` //非必传 String 32 提款类型 01主动提款03交易自动结算不填默认01
Attachments []AttachmentsList `json:"attachments"` //可选 集合附加资料 其它附加资料文件信息}
}
type AttachmentsList struct {
AttachType string `json:"attachType"` //必传 String 32 附件类型编码
AttachName string `json:"attachName"` //必传 String 32 附件名称
AttachStorePath string `json:"attachStorePath"` //必传 String 128 附件路径
}
// CreateSeparateResp 创建分账返回信息
type CreateSeparateResp struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
RespData struct {
Version string `json:"version"`
OrderNo string `json:"orderNo"`
OrgCode string `json:"orgCode"`
ApplyId int64 `json:"applyId"`
} `json:"respData"`
}
// SeparateModifyReq 商户申请变更分账商户
type SeparateModifyReq struct {
Version string `json:"version"` // 必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` // 必传 String 32 订单编号(便于后续跟踪排查问题及回调消息匹配)) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` // 必传 String 32 机构代码
MerInnerNo string `json:"merInnerNo"` // 可选 String 32 拉卡拉内部商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
MerCupNo string `json:"merCupNo"` // 可选 String 32 银联商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
ContactMobile string `json:"contactMobile"` // 可选 String 32 联系手机号
SplitLowestRatio string `json:"splitLowestRatio"` // 可选 String 32 最低分账比例百分比支持2位精度 70 或 70.50
SplitEntrustFileName string `json:"splitEntrustFileName"` // 可选 String 64 分账结算委托书文件名称 变更比例必传,分账结算委托书文件名称.pdf
SplitEntrustFilePath string `json:"splitEntrustFilePath"` // 可选 String 64 分账结算委托书文件路径 变更比例必传,调用商户入网接口上传附件后反馈的文件路径: 文件上传
SplitRange string `json:"splitRange"` // 非必传 String 32 分账范围 ALL商户全量交易自动分账处理 MARK按交易请求分账标识进行分账处理
SplitRuleSource string `json:"splitRuleSource"` // 非必传 String 32 分账规则来源 MER商户分账规则 PLATFORM平台分账规则
RetUrl string `json:"retUrl"` // 必传 String 128 回调通知地址 审核通过后通知的地址
EleContractNo string `json:"eleContractNo"` // 非必传 String 32 电子合同编号 如果已经签署过电子合同此处上送电子合同编号即可,供审核人员复核使用。
Attachments []AttachmentsList `json:"attachments"` //可选 集合附加资料 其它附加资料文件信息}
}
// SeparateQueryReq 商户分账信息查询
type SeparateQueryReq struct {
Version string `json:"version"` // 必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` // 必传 String 32 订单编号(便于后续跟踪排查问题及回调消息匹配)) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` // 必传 String 32 机构代码
MerInnerNo string `json:"merInnerNo"` // 可选 String 32 拉卡拉内部商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
MerCupNo string `json:"merCupNo"` // 可选 String 32 银联商户号 拉卡拉内部商户号和银联商户号必须传一个,都送以内部商户号为准
}
// SeparateQueryResp 商户分账信息查询返回值
type SeparateQueryResp struct {
OrgId string `json:"orgId"` // 分账商户机构号
OrgName string `json:"orgName"` // 分账商户机构名称
MerInnerNo string `json:"merInnerNo"` // 拉卡拉内部商户号
MerCupNo string `json:"merCupNo"` // 银联商户号
SplitLowestRatio string `json:"splitLowestRatio"` // 最低分账比例百分比支持2位精度 70 或 70.50
SplitStatus string `json:"splitStatus"` // 商户分账状态 VALID 启用INVALID 禁用
SplitRange string `json:"splitRange"` // 分账范围 ALL全部交易分账 (商户所有交易默认待分账)MARK标记交易分账(只有带分账标识交易待分账,其余交易正常结算)默认MARK
SepFundSource string `json:"sepFundSource"` // 分账依据 TR或空交易分账BA余额分账默认TR 交易分账
PlatformId string `json:"platformId"` // 平台ID 如果商户和绑定平台分账则返回平台ID
SplitLaunchMode string `json:"splitLaunchMode"` // 分账发起方式 AUTO自动规则分账POINTRULE指定规则分账MANUAL 手动规则分账
SplitRuleSource string `json:"splitRuleSource"` // 分账规则来源 MER商户分账规则PLATFORM平台分账规则
BindRelations []bindRelationsList `json:"bindRelations"` // 集合 已绑定接收方列表
}
type bindRelationsList struct {
MerInnerNo string `json:"merInnerNo"` // 拉卡拉内部商户号
MerCupNo string `json:"merCupNo"` // 银联商户号
ReceiverNo string `json:"receiverNo"` // 接收方编号
ReceiverName string `json:"receiverName"` // 接收方编号名称
}
// CreateSeparateRecipientReq 创建分账接收方参数
type CreateSeparateRecipientReq struct {
Version string `json:"version"` // 必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` // 必传 String 32 订单编号(便于后续跟踪排查问题及核对报文) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` // 必传 String 32 机构代码
ReceiverName string `json:"receiverName"` // 必传 String 64 分账接收方名称
ContactMobile string `json:"contactMobile"` // 必传 String 16 联系手机号
LicenseNo string `json:"licenseNo"` // 可选 String 32 营业执照号码 收款账户账户类型为对公,必须上送
LicenseName string `json:"licenseName"` // 可选 String 128 营业执照名称 收款账户账户类型为对公,必须上送
LegalPersonName string `json:"legalPersonName"` // 可选 String 32 法人姓名 收款账户账户类型为对公,必须上送
LegalPersonCertificateType string `json:"legalPersonCertificateType"` // 可选 String 32 法人证件类型 17 身份证18 护照19 港澳居民来往内地通行证 20 台湾居民来往内地通行证 收款账户账户类型为对公,必须上送,身份证外类型先咨询后再使用
LegalPersonCertificateNo string `json:"legalPersonCertificateNo"` // 可选 String 32 法人证件号 收款账户账户类型为对公,必须上送
AcctNo string `json:"acctNo"` // 必传 String 32 收款账户卡号
AcctName string `json:"acctName"` // 必传 String 32 收款账户名称
AcctTypeCode string `json:"acctTypeCode"` // 必传 String 32 收款账户账户类型 57对公 58对私
AcctCertificateType string `json:"acctCertificateType"` // 必传 String 32 收款账户证件类型 17 身份证18 护照19 港澳居民来往内地通行证 20 台湾居民来往内地通行证 身份证外类型先咨询后再使用
AcctCertificateNo string `json:"acctCertificateNo"` // 必传 String 32 收款账户证件号
AcctOpenBankCode string `json:"acctOpenBankCode"` // 必传 String 32 收款账户开户行号 参照卡BIN信息查询仅支持对私结算账户
AcctOpenBankName string `json:"acctOpenBankName"` // 必传 String 64 收款账户开户名称
AcctClearBankCode string `json:"acctClearBankCode"` // 必传 String 32 收款账户清算行行号 参照卡BIN信息查询仅支持对私结算账户
AttachList []AttachList `json:"attachList"` // 可选 集合 接收方附件资料
AttachType string `json:"attachType"` // 可选 String 32 附件类型编码
AttachName string `json:"attachName"` // 可选 String 32 附件名称
AttachStorePath string `json:"attachStorePath"` // 可选 String 32 附件路径 (调用进件附件上传接口获取到附件路径) 文件上传
SettleType string `json:"settleType"` // 可选 String 32 提款类型 01主动提款03交易自动结算 不填默认01
}
type AttachList struct {
AttachName string `json:"attachName"` // 附件文件名称
AttachStorePath string `json:"attachStorePath"` // 文件路径
AttachType string `json:"attachType"` // 附件ID
}
// CreateSeparateRecipientResp 创建分账账户
type CreateSeparateRecipientResp struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
RespData struct {
Version string `json:"version"`
OrderNo string `json:"orderNo"`
OrgCode string `json:"orgCode"`
OrgId string `json:"orgId"`
OrgName string `json:"orgName"`
ReceiverNo string `json:"receiverNo"`
} `json:"respData"`
}
// QuerySeparateRecipientResp 分账接收方信息查询
type QuerySeparateRecipientResp struct {
ReceiverNo string `json:"receiverNo"` // 接收方编号
ReceiverName string `json:"receiverName"` // 分账接收方名称
ContactMobile string `json:"contactMobile"` // 联系手机号
LicenseNo string `json:"licenseNo"` // 营业执照号码
LicenseName string `json:"licenseName"` // 营业执照名称
LegalPersonName string `json:"legalPersonName"` // 法人姓名
LegalPersonCertificateType string `json:"legalPersonCertificateType"` // 法人证件类型 17 身份证18 护照19 港澳居民来往内地通行证 20 台湾居民来往内地通行证
LegalPersonCertificateNo string `json:"legalPersonCertificateNo"` // 法人ID号
AcctNo string `json:"acctNo"` // 收款账户卡号
AcctName string `json:"acctName"` // 收款账户名称
AcctTypeCode string `json:"acctTypeCode"` // 收款账户账户类型
AcctCertificateType string `json:"acctCertificateType"` // 收款证件类型 17 身份证18 护照19 港澳居民来往内地通行证 20 台湾居民来往内地通行证
AcctCertificateNo string `json:"acctCertificateNo"` // 收款账户证件号
AcctOpenBankCode string `json:"acctOpenBankCode"` // 收款账户开户行号
AcctOpenBankName string `json:"acctOpenBankName"` // 收款账户开户名称
AcctClearBankCode string `json:"acctClearBankCode"` // 收款账户清算行行号
//RowStatus interface{} `json:"rowStatus"`
//RowSno string `json:"rowSno"`
//RowCreateUser interface{} `json:"rowCreateUser"`
//RowCreateUserName string `json:"rowCreateUserName"`
//RowCreateTm time.Time `json:"rowCreateTm"`
//RowModifyUser interface{} `json:"rowModifyUser"`
//RowModifyUserName interface{} `json:"rowModifyUserName"`
//RowModifyTm time.Time `json:"rowModifyTm"`
//RowVerNo interface{} `json:"rowVerNo"`
//Id int `json:"id"`
//SettlePeriod interface{} `json:"settlePeriod"`
//SettleModel interface{} `json:"settleModel"`
//ClearDt interface{} `json:"clearDt"`
//OrgId string `json:"orgId"`
//OrgName string `json:"orgName"`
//OrgPath string `json:"orgPath"`
//ReceiverStatus interface{} `json:"receiverStatus"`
//WalletId string `json:"walletId"`
//Remark interface{} `json:"remark"`
}
// SeparateApplyBindReq 分账关系申请绑定
type SeparateApplyBindReq struct {
Version string `json:"version"`
OrderNo string `json:"orderNo"` // 订单编号(便于后续跟踪排查问题及核对报文)
OrgCode string `json:"orgCode"` // 分账接收方所属机构代码
MerInnerNo string `json:"merInnerNo"` // 分账商户内部商户号
MerCupNo string `json:"merCupNo"` // 分账商户银联商户号
ReceiverNo string `json:"receiverNo"` // 分账接收方编号
EntrustFileName string `json:"entrustFileName"` // 合作协议附件名称
EntrustFilePath string `json:"entrustFilePath"` // 合作协议附件路径
RetUrl string `json:"retUrl"` // 回调通知地址
Attachments []AttachList `json:"attachments"` // 其它附加资料文件信息
}
// SeparateApplyBindResp 申请绑定返回值
type SeparateApplyBindResp struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
RespData struct {
Version string `json:"version"`
OrderNo string `json:"orderNo"`
OrgCode string `json:"orgCode"`
ApplyId int64 `json:"applyId"`
} `json:"respData"`
}
// SeparateUnBindReq 申请解除分账绑定
type SeparateUnBindReq struct {
Version string `json:"version"` // 必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` // 必传 String 32 订单编号(便于后续跟踪排查问题及核对报文) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` // 必传 String 32 分账接收方所属机构代码
MerInnerNo string `json:"merInnerNo"` // 必传 String 32 分账商户内部商户号 merInnerNo、merCupNo选传其一不能都为空
MerCupNo string `json:"merCupNo"` // 必传 String 32 分账商户银联商户号 merInnerNo、merCupNo选传其一不能都为空
ReceiverNo string `json:"receiverNo"` // 必传 String 32 分账接收方编号
EntrustFileName string `json:"entrustFileName"` // 必传 String 32 解除分账说明附件名称
EntrustFilePath string `json:"entrustFilePath"` // 必传 String 32 解除分账说明附件路径 (调用进件附件上传接口获取到附件路径) 文件上传
Remark string `json:"remark"` // 必传 String 128 备注说明
RetUrl string `json:"retUrl"` // 必传 String 128 回调通知地址 审核通过后通知的地址
}
// UpdateSeparateRecipientReq 修改分账接收方参数
type UpdateSeparateRecipientReq struct {
Version string `json:"version"` // 必传 String 8 接口版本号 1.0
OrderNo string `json:"orderNo"` // 必传 String 32 订单编号(便于后续跟踪排查问题及核对报文) 14位年月日时24小时制分秒+8位的随机数不重复2021020112000012345678
OrgCode string `json:"orgCode"` // 必传 String 32 机构代码
ReceiverNo string `json:"receiverNo"` // 必传 分账接收方编号
ReceiverName string `json:"receiverName"` // 必传 String 64 分账接收方名称
ContactMobile string `json:"contactMobile"` // 必传 String 16 联系手机号
AcctNo string `json:"acctNo"` // 必传 String 32 收款账户卡号
AcctTypeCode string `json:"acctTypeCode"` // 必传 String 32 收款账户账户类型 57对公 58对私
AcctOpenBankCode string `json:"acctOpenBankCode"` // 必传 String 32 收款账户开户行号 参照卡BIN信息查询仅支持对私结算账户
AcctOpenBankName string `json:"acctOpenBankName"` // 必传 String 64 收款账户开户名称
AcctClearBankCode string `json:"acctClearBankCode"` // 必传 String 32 收款账户清算行行号 参照卡BIN信息查询仅支持对私结算账户
AttachList []AttachList `json:"attachList"` // 可选 集合 接收方附件资料
AttachType string `json:"attachType"` // 可选 String 32 附件类型编码
AttachName string `json:"attachName"` // 可选 String 32 附件名称
AttachStorePath string `json:"attachStorePath"` // 文件路径
Status string `json:"status"` // 接收方状态 有效VALID 无效INVALID
}
// OrderSeparateReq 订单分账
type OrderSeparateReq struct {
MerchantNo string `json:"merchant_no"` // M String 32 商户号
LogNo string `json:"log_no"` // M String 14 拉卡拉对账单流水号 posp流水号查清结算用
LogDate string `json:"log_date"` // M String 8 交易日期 posp日期yyyyMMdd查清结算用
OutSeparateNo string `json:"out_separate_no"` // M String 32 商户分账指令流水号 商户分账指令流水号,每个商户号下唯一,否则会校验失败
TotalAmt string `json:"total_amt"` // M String 15 分账总金额 [单位:分]
LklOrgNo string `json:"lkl_org_no"` // C String 16 拉卡拉机构编号
CalType string `json:"cal_type"` // C String 2 分账计算类型 0- 按照指定金额1- 按照指定比例。默认 0
NotifyUrl string `json:"notify_url"` // C String 128 回调地址 分账,分账撤销或分账回退时,是异步接口。通过该地址通知商户最终处理结果。不传时,不回调
RecvDatas []RecvDatasParam `json:"recv_datas"` // C List 分账接收数据对象 分账接收方编号必须已创建
}
// RecvDatasParam 分账接收数据对象
type RecvDatasParam struct {
RecvMerchantNo string `json:"recv_merchant_no"` // C String 32 接收方商户号 分账接收方商户号分给自己时使用需和merchantNo一样否则检查报错分账接收方商户号 和 分账接收方 只能填写一个。
RecvNo string `json:"recv_no"` // C String 32 分账接收方编号 分账接收方编号, 分给他人时使用;分账接收方商户号 和 分账接收方 只能填写一个。
SeparateValue string `json:"separate_value"` // M String 32 分账数值 calType为0时按照固定金额分账单位分 calType为1时按照比例分账单位百分比的小数值比如0.55 55%
}
// OrderSeparateResp 分账结束返回
type OrderSeparateResp struct {
Msg string `json:"msg"`
RespTime string `json:"resp_time"`
Code string `json:"code"`
RespData struct {
TotalAmt string `json:"total_amt"` // 分账总金额
LogDate string `json:"log_date"` // 拉卡拉订单日期
SeparateNo string `json:"separate_no"` // 分账指令流水号
LogNo string `json:"log_no"` // 拉卡拉对账单流水号
OutSeparateNo string `json:"out_separate_no"` // 商户订单号
Status string `json:"status"` // 分账状态 处理中PROCESSING, 已受理ACCEPTED, 成功SUCCESS, 失败FAIL
} `json:"resp_data"`
}
// SeparateCancelReq 订单分账撤销请求参数
type SeparateCancelReq struct {
MerchantNo string `json:"merchant_no"` // 分账方商户号
OriginSeparateNo string `json:"origin_separate_no"` // 分账指令接口返回的分账流水origin_out_separate_no和该字段至少二选一优先级: origin_separate_no> origin_out_separate_no
OriginOutSeparateNo string `json:"origin_out_separate_no"` // 分账指令请求时入参中的origin_separate_no该字段至少二选一优先级: origin_separate_no> origin_out_separate_no
OutSeparateNo string `json:"out_separate_no"` // 商户分账指令流水号
TotalAmt string `json:"total_amt"` // 撤销金额
}
// SeparateCancelResp 订单分账撤销返回参数
type SeparateCancelResp struct {
Msg string `json:"msg"`
RespTime string `json:"resp_time"`
Code string `json:"code"`
RespData struct {
TotalAmt string `json:"total_amt"` // 撤销金额 单位:分 和分账总金额一致,否则校验报错
SeparateNo string `json:"separate_no"` // 分账撤销流水号 分账系统生成,系统唯一
OriginSeparateNo string `json:"origin_separate_no"` // 原分账指令流水 请求透返
OutSeparateNo string `json:"out_separate_no"` // 商户分账指令流水号 请求透返
OriginOutSeparateNo string `json:"origin_out_separate_no"` // 原商户分账指令流水号 请求透返
Status string `json:"status"` // 分账状态 处理中PROCESSING, 已受理ACCEPTED, 成功SUCCESS, 失败FAIL
} `json:"resp_data"`
}
// SeparateFallReq 分账退回请求参数
type SeparateFallReq struct {
MerchantNo string `json:"merchant_no"` // 分账方商户号
OriginSeparateNo string `json:"origin_separate_no"` // 分账指令接口返回的分账流水origin_out_separate_no和该字段至少二选一优先级: origin_separate_no> origin_out_separate_no
OutSeparateNo string `json:"out_separate_no"` // 商户分账指令流水号
OriginOutSeparateNo string `json:"origin_out_separate_no"` // 分账指令请求时入参中的origin_separate_no该字段至少二选一优先级: origin_separate_no> origin_out_separate_no
FallbackReason string `json:"fallback_reason"` // 回退原因
TotalAmt string `json:"total_amt"` // 撤销金额
OriginRecvDatas []*OriginRecvDatas `json:"origin_recv_datas"` // 原分账接收数据对象
}
type OriginRecvDatas struct {
RecvNo string `json:"recv_no"` // 分账接收方编号
Amt string `json:"amt"` // 回退金额
}
// SeparateFallResp 分账退回响应参数
type SeparateFallResp struct {
Msg string `json:"msg"`
RespTime string `json:"resp_time"`
Code string `json:"code"`
RespData struct {
TotalAmt string `json:"total_amt"` // 回退金额
SeparateNo string `json:"separate_no"` // 分账回退流水号
OriginSeparateNo string `json:"origin_separate_no"` // 原分账指令流水号
OriginOutSeparateNo string `json:"origin_out_separate_no"` // 原商户分账指令请求流水号
OutSeparateNo string `json:"out_separate_no"` // 商户分账指令请求流水号
Status string `json:"status"` // 原分账指令流水号
} `json:"resp_data"`
}
// SeparateResultQueryResp 分账结构查询
type SeparateResultQueryResp struct {
SeparateNo string `json:"separate_no"` //
OutSeparateNo string `json:"out_separate_no"` //
CmdType string `json:"cmd_type"` // 指令类型 SEPARATE分账 CANCEL分账撤销 FALLBACK分账回退
LogNo string `json:"log_no"` //
LogDate string `json:"log_date"` //
CalType string `json:"cal_type"` // 分账计算类型 0 按照指定金额。1 按照指定比例,默认 0 cmd_type为SEPARATE分账指令类型才有值
SeparateDate string `json:"separate_date"` //
FinishDate string `json:"finish_date"` //
TotalAmt string `json:"total_amt"` //
Status string `json:"status"` // 分账状态 ACCEPTED:已受理, PROCESSING:处理中, FAIL:失败, SUCCESS:成功, 如果分账指令后有反向操作指令则原分账指令会变更成以下的状态之一CANCELING:撤销中, CANCELED:撤销成功, CANCEL_FAIL:撤销失败, FALLBACKING:回退中, FALLBACK_END:回退结束
FinalStatus string `json:"final_status"` // 处理状态 ACCEPTED:已受理, PROCESSING:处理中, FAIL:失败, SUCCESS:成功
FrontRuleId string `json:"front_rule_id"` // 分账前置规则ID
ActualSeparateAmt string `json:"actual_separate_amt"` // 实分金额 若该笔分账收取手续费,则该字段有值
TotalFeeAmt string `json:"total_fee_amt"` // 手续费金额
DetailDatas []struct {
RecvMerchantNo string `json:"recv_merchant_no"` // 接收方商户号
RecvNo string `json:"recv_no"` // 接收方编号
Amt string `json:"amt"` // 分账金额
} `json:"detail_datas"` // 明细数据
SeparateType string `json:"separate_type"` //
}
// SeparateQueryAmtResp 可分账金额查询
type SeparateQueryAmtResp struct {
MerchantNo string `json:"merchant_no"` // 商户号
TotalSeparateAmt string `json:"total_separate_amt"` // 总分账金额
CanSeparateAmt string `json:"can_separate_amt"` // 可分账金额
LogDate string `json:"log_date"` // 拉卡拉对账单交易日期
LogNo string `json:"log_no"` // 拉卡拉对账单流水号
}

View File

@@ -0,0 +1,44 @@
package lakala
import (
"testing"
)
func TestCreateSeparate(t *testing.T) {
parameter := &CreateSeparateReq{
Version: "1.0",
OrderNo: "KFPT20230223181025407788734",
OrgCode: "1",
MerInnerNo: "4002021033012340711",
MerCupNo: "822*******",
ContactMobile: "111111",
SplitLowestRatio: 0,
SplitEntrustFileName: "授权委托书.pdf",
SplitEntrustFilePath: "G1/M00/00/16/CrFdEl0wGu6AHwGQAAAz1tt6luo194.jpg",
RetUrl: "http://run.mocky.io/v3/b02c9448-20a2-4ff6-a678-38ecab30161d",
SplitRuleSource: "",
SplitRange: "",
SepFundSource: "",
EleContractNo: "",
SplitLaunchMode: "",
SettleType: "",
Attachments: nil,
}
api.CreateSeparate(parameter)
}
func TestGetSeparate(t *testing.T) {
paramter := &SeparateQueryReq{
Version: "1.0",
OrderNo: "KFPT20230223181747812863750",
OrgCode: "1",
MerInnerNo: "822*********",
MerCupNo: "",
}
api.SeparateQuery(paramter)
}
func TestQuerySeparateRecipient(t *testing.T) {
api.QuerySeparateRecipient("NEWRETAILSPLIT26687958", "4002022021832894453")
}

View File

@@ -0,0 +1,236 @@
package lakala
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"github.com/tjfoc/gmsm/sm4"
"io"
"io/ioutil"
"math/big"
"mime/multipart"
"net/http"
"strings"
"time"
)
// IncomingToken 进件api,token获取
func (a *API) IncomingToken() (comingToken string, expiresIn int64, err error) {
result, err := a.AccessAPI(IncomingUrlTest, TokenActive, http.MethodPost, "", map[string]interface{}{
"grant_type": "client_credentials",
"client_id": a.clientId,
"client_secret": a.clientSecret,
})
if err != nil {
return "", 0, err
}
expiresIn, err = utils.TryInterface2Int64(result["expires_in"])
if err != nil {
return "", 0, err
}
a.incomingToken = result["access_token"].(string)
a.incomingExpire = time.Now().Unix() + expiresIn
return a.incomingToken, a.incomingExpire, nil
}
// ModifiedToken 更新token获取
func (a *API) ModifiedToken(userName string, password string) (modifiedToken string, modifiedExpire int64, err error) {
result, err := a.AccessAPI(IncomingUrlTest, TokenActive, http.MethodPost, "", map[string]interface{}{
"grant_type": "password",
"username": userName,
"password": password,
})
if err != nil {
return "", 0, err
}
modifiedExpire, err = utils.TryInterface2Int64(result["expires_in"])
if err != nil {
return "", 0, err
}
a.modifiedToken = result["access_token"].(string)
a.modifiedExpire = time.Now().Unix() + modifiedExpire
return a.modifiedToken, a.modifiedExpire, nil
}
// FileUpload 文件上传下载 filePath:文件url,由于controller:swagger不支持文件类型
func (a *API) FileUpload(filePath, imgType, sourcechnl, isOcr string) (*UploadImgResp, error) {
client := &http.Client{}
// 获取问价
resp, err := client.Get(filePath)
if err != nil {
return nil, err
}
imgData, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
// 创建一个缓冲区来构建 multipart 请求
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 添加文件到 multipart 请求
part, err := writer.CreateFormFile("file", filePath)
if err != nil {
return nil, err
}
_, err = io.Copy(part, strings.NewReader(string(imgData)))
if err != nil {
return nil, err
}
// 添加其他表单字段
writer.WriteField("imgType", imgType)
writer.WriteField("sourcechnl", sourcechnl)
writer.WriteField("isOcr", isOcr)
// 关闭 writer
err = writer.Close()
if err != nil {
return nil, err
}
// 创建 HTTP 请求
req, err := http.NewRequest("POST", fmt.Sprintf("%s/%s", BaseTestUrl, FileUpload), body)
if err != nil {
return nil, err
}
// 设置 Content-Type 头
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", fmt.Sprintf("bearer %s", a.incomingToken))
// 发送请求
resp, err = client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// 读取响应
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
img := &UploadImgResp{}
json.Unmarshal(data, img)
return img, err
}
type UploadImgResp struct {
BatchNo interface{} `json:"batchNo"` // 批量号
Status string `json:"status"` // 00 成功, 01 正在处理中, 02 失败
Url string `json:"url"` // 拉卡拉文件地址
ShowUrl string `json:"showUrl"` // 拉卡拉文件url
Result interface{} `json:"result"` //
}
// signParamRSA 支付签名
func (a *API) signParamRSA(params map[string]interface{}, RSAPrivate string) (sig string, err error) {
block, _ := pem.Decode([]byte(RSAPrivate))
private, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// 签名参数
body, err := json.Marshal(params)
if err != nil {
return "", err
}
//bodyData := base64.StdEncoding.EncodeToString(body)
nonceStr := GenerateSecureRandomString(12)
timeStamp := utils.Int64ToStr(time.Now().Unix())
context := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n", a.appID, a.serialNo, timeStamp, nonceStr, string(body))
// 进行rsa加密签名
hashed := sha256.Sum256([]byte(context))
signedData, err := rsa.SignPKCS1v15(rand.Reader, private.(*rsa.PrivateKey), crypto.SHA256, hashed[:])
if err != nil {
return "", err
}
signData := base64.StdEncoding.EncodeToString(signedData)
authorization := fmt.Sprintf(`LKLAPI-SHA256withRSA appid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"`, a.appID, a.serialNo, timeStamp, nonceStr, signData)
return authorization, nil
}
// GenerateSecureRandomString 获取随机字符串
func GenerateSecureRandomString(length int) string {
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
bytes := make([]byte, length)
charSetSize := big.NewInt(int64(len(charset)))
for i := range bytes {
num, _ := rand.Int(rand.Reader, charSetSize)
bytes[i] = charset[num.Int64()]
}
return string(bytes)
}
func GetOrderNumber(length int) string {
charset := "0123456789"
bytes := make([]byte, length)
charSetSize := big.NewInt(int64(len(charset)))
for i := range bytes {
num, _ := rand.Int(rand.Reader, charSetSize)
bytes[i] = charset[num.Int64()]
}
return utils.Time2TimeStrByFormat(time.Now(), TimeFormat) + string(bytes)
}
func SM4ECBEncrypt(plaintext, key []byte) ([]byte, error) {
if len(key) != sm4.BlockSize {
return nil, fmt.Errorf("SM4 密钥长度必须为 %d 字节", sm4.BlockSize)
}
// 补位处理 (PKCS5Padding)
paddedText := PKCS5Padding(plaintext, sm4.BlockSize)
// ECB 模式加密
ciphertext := make([]byte, len(paddedText))
for i := 0; i < len(paddedText); i += sm4.BlockSize {
block := paddedText[i : i+sm4.BlockSize]
encryptedBlock, err := sm4.Sm4Ecb(key, block, true) // true 表示加密
if err != nil {
return nil, err
}
copy(ciphertext[i:], encryptedBlock)
}
return ciphertext, nil
}
// PKCS5Padding 填充(与 PKCS7Padding 对于 128位分组等价
func PKCS5Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padtext...)
}
type CallBackResult struct {
Code string `json:"code"`
Message string `json:"message"`
}
// CallBackResultInfo 失败回调返回
func CallBackResultInfo(err error) *CallBackResult {
if err == nil {
return &CallBackResult{
Code: "SUCCESS",
Message: "执行成功",
}
}
return &CallBackResult{
Code: "400",
Message: err.Error(),
}
}

View File

@@ -0,0 +1,96 @@
package lakala
const (
LaKaLaPrivateKey = `-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDvDBZyHUDndAGx
rIcsCV2njhNO3vCEZotTaWYSYwtDvkcAb1EjsBFabXZaKigpqFXk5XXNI3NIHP9M
8XKzIgGvc65NpLAfRjVql8JiTvLyYd1gIUcOXMInabu+oX7dQSI1mS8XzqaoVRhD
ZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si+hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbW
dhZ+NHwitnQwAJTLBFvfk28INM39G7XOsXdVLfsooFdglVTOHpNuRiQAj9gShCCN
rpGsNQxDiJIxE43qRsNsRwigyo6DPJk/klgDJa417E2wgP8VrwiXparO4FMzOGK1
5quuoD7DAgMBAAECggEBANhmWOt1EAx3OBFf3f4/fEjylQgRSiqRqg8Ymw6KGuh4
mE4Md6eW/B6geUOmZjVP7nIIR1wte28M0REWgn8nid8LGf+v1sB5DmIwgAf+8G/7
qCwd8/VMg3aqgQtRp0ckb5OV2Mv0h2pbnltkWHR8LDIMwymyh5uCApbn/aTrCAZK
NXcPOyAn9tM8Bu3FHk3Pf24Er3SN+bnGxgpzDrFjsDSHjDFT9UMIc2WdA3tuMv9X
3DDn0bRCsHnsIw3WrwY6HQ8mumdbURk+2Ey3eRFfMYxyS96kOgBC2hqZOlDwVPAK
TPtS4hoq+cQ0sRaJQ4T0UALJrBVHa+EESgRaTvrXqAECgYEA+WKmy9hcvp6IWZlk
9Q1JZ+dgIVxrO65zylK2FnD1/vcTx2JMn73WKtQb6vdvTuk+Ruv9hY9PEsf7S8gH
STTmzHOUgo5x0F8yCxXFnfji2juoUnDdpkjtQK5KySDcpQb5kcCJWEVi9v+zObM0
Zr1Nu5/NreE8EqUl3+7MtHOu1TMCgYEA9WM9P6m4frHPW7h4gs/GISA9LuOdtjLv
AtgCK4cW2mhtGNAMttD8zOBQrRuafcbFAyU9de6nhGwetOhkW9YSV+xRNa7HWTeI
RgXJuJBrluq5e1QGTIwZU/GujpNaR4Qiu0B8TodM/FME7htsyxjmCwEfT6SDYlke
MzTbMa9Q0DECgYBqsR/2+dvD2YMwAgZFKKgNAdoIq8dcwyfamUQ5mZ5EtGQL2yw4
8zibHh/LiIxgUD1Kjk/qQgNsX45NP4iOc0mCkrgomtRqdy+rumbPTNmQ0BEVJCBP
scd+8pIgNiTvnWpMRvj7gMP0NDTzLI3wnnCRIq8WAtR2jZ0Ejt+ZHBziLQKBgQDi
bEe/zqNmhDuJrpXEXmO7fTv3YB/OVwEj5p1Z/LSho2nHU3Hn3r7lbLYEhUvwctCn
Ll2fzC7Wic1rsGOqOcWDS5NDrZpUQGGF+yE/JEOiZcPwgH+vcjaMtp0TAfRzuQEz
NzV8YGwxB4mtC7E/ViIuVULHAk4ZGZI8PbFkDxjKgQKBgG8jEuLTI1tsP3kyaF3j
Aylnw7SkBc4gfe9knsYlw44YlrDSKr8AOp/zSgwvMYvqT+fygaJ3yf9uIBdrIilq
CHKXccZ9uA/bT5JfIi6jbg3EoE9YhB0+1aGAS1O2dBvUiD8tJ+BjAT4OB0UDpmM6
QsFLQgFyXgvDnzr/o+hQJelW
-----END PRIVATE KEY-----
`
LaKaLaPublicKey = `-----BEGIN CERTIFICATE-----
MIIDYTCCAkmgAwIBAgIJAN+6gZTEG4TPMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV
BAYTAlVTMREwDwYDVQQIEwhzaGFuZ2hhaTERMA8GA1UEBxMIc2hhbmdoYWkxFDAS
BgNVBAMUC2xha2FsYV8yMDIxMB4XDTIxMDYxODA3MjEzNFoXDTMxMDYxOTA3MjEz
NFowSTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCHNoYW5naGFpMREwDwYDVQQHEwhz
aGFuZ2hhaTEUMBIGA1UEAxQLbGFrYWxhXzIwMjEwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDvDBZyHUDndAGxrIcsCV2njhNO3vCEZotTaWYSYwtDvkcA
b1EjsBFabXZaKigpqFXk5XXNI3NIHP9M8XKzIgGvc65NpLAfRjVql8JiTvLyYd1g
IUcOXMInabu+oX7dQSI1mS8XzqaoVRhDZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si
+hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbWdhZ+NHwitnQwAJTLBFvfk28INM39G7XO
sXdVLfsooFdglVTOHpNuRiQAj9gShCCNrpGsNQxDiJIxE43qRsNsRwigyo6DPJk/
klgDJa417E2wgP8VrwiXparO4FMzOGK15quuoD7DAgMBAAGjTDBKMAkGA1UdEwQC
MAAwEQYJYIZIAYb4QgEBBAQDAgTwMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggr
BgEFBQcDAgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAI21YYAlH+Pc1ISv
nbQrGqL8suGL0Hh/8hGaFfrJEJEKr9OeC8jElUhck2MTmfu/Y1lB7r8RBrhGPXi4
kTXmB6ADs/9+ezNW3WXyFj7fhs3JcZ3mo33T9wyQySDKd//JrEtrTsc/s2PZ602y
qNmPomXSzjrlugaMyC7LI9sR44mc7sQnchjHoxrQFD5/usTFW72UQfYCORsQWYMt
0KKEyAcpRL51RE3xbX1WDtduFYGP62PbwLAn2nCL/j1wlF5hltWj7sditWqKgso5
F8BTffn2Bb0RdsNxqwMy1cTPrWLeXVOqMDu3ge7hvoav8lZKTjk5Kmqhs7wNAQXK
mg9qSwo=
-----END CERTIFICATE-----
`
)
// 私钥文件目录C:\Users\Administrator\Desktop\拉克拉\拉卡拉私钥生成\RSA密钥生成工具V1.0.0\RSAKeys
const (
AppID = "OP00000003" // 接入方唯一ID lakala分配
SerialNo = "00dfba8194c41b84cf" // 接入方生成的cer证书序列号 lakala分配
SM4Key = "LHo55AjrT4aDhAIBZhb5KQ==" // 国密4-参数加密使用 lakala分配
MerchantNo = "82229007392000A" // 商户号 商户进件产生
TermNo = "D9296400" // 终端号 商户进件产生
OrgCode = "200669" // 终端号 商户进件产生
)
// 测试参数
const (
ClientID = "testsit"
ClientSecret = "EguwEckByf2I6u6z"
UserName = "13200000001"
Password = `klik13!@`
BusiCode = "ZPOS4G"
ActivityId = 4
UserNo = "20000101"
PublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp5aV3ZiXG2R8Yd8Nxocv+cF7VAUHBc0TF4MNne7mI8wM2yEP2QgI+rK1qDf6G7ZFPhutpIHKQchpolbSuC0vgaHpSjO9OUs1fpnK/JjZq9o8DatUsA0n4Fccec9NBbV5dy5yrwro7xmDpsevp1/IeiIssi1+iD+nBWqqVFx7GVQIDAQAB"
PrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKnlpXdmJcbZHxh3w3Ghy/5wXtUBQcFzRMXgw2d7uYjzAzbIQ/ZCAj6srWoN/obtkU+G62kgcpByGmiVtK4LS+BoelKM705SzV+mcr8mNmr2jwNq1SwDSfgVxx5z00FtXl3LnKvCujvGYOmx6+nX8h6IiyyLX6IP6cFaqpUXHsZVAgMBAAECgYA4NpeM7etJ48T6H4Y3LsWEJkH6UDQlgbIblsaQkstMmLtTgOebrzN28UNfd8njcu9FVOrHGclOKbK7L+1cOLiduWsZKc/c/gAy9wAR4EhoLvlerH9EEPiPWFxdEDbMxPqlkpqLOo+PxHrhTn4vU4CaPdJtL2ujKn7nmsUdUDWo8QJBANS1TlM6nhPt2XlzN5kGfsJ4kBYNjuLXNA2YdNuC2ttYvEXHJ9T70FN/GnRBBIZu47uHH3Ie5nfep+qMk6a8RP8CQQDMecIyI0z1kVt+tOfWKw2ZFLsi74708qTaeR4W1ABtkngj1+bxoWWXr3KqhjqJkWxnhioSfXqu7CScNzjdM1CrAkAQd+ESjI1EmbumrYb2cAxMXi05p98SLPs4uj8B58WuCda5yEuLL9vXOxX/PjFtfxRepn2GxmGtki2J+UxNMnJdAkAFoORjlO0tZU7rcfdfwdeh+xwbnhSFUZiQGv1lC3jnizybX/oPdK3jOwUhBIjf+IzPXLYTxDh4UC/BzRNXo235AkEAhgYBk6H7RU2iIuvwz1c6CtE1gJ8DvEp1F0KOMWMFB0KCpDXUToix0dlMz962FozYENi4X4zYQo6nFwlXeS3Pfw=="
)
// token访问路由
const (
IncomingUrlTest = "https://test.wsmsd.cn/sit/htkauth/oauth" // 进件获取token测试地址,变更接口token测试地址
TokenActive = "token"
IncomingUrlProd = "https://tkapi.lakala.com/auth/oauth" // 进件获取token正式地址
ModifiedUrlProd = "https://htkapi.lakala.com/auth/oauth" // 变更接口token正式地址
)
const (
CallbackLaKaLaShopUrl = "http://callback.jxc4.com/lakalaCallback/separateMsg" // 消息通知地址(商户开通)
CallbackLaKaLaSeparateBindUrl = "http://callback.jxc4.com/lakalaCallback/separateBind" // 消息通知地址(分账关系绑定回调,解绑回调)
CallbackLaKaLaSeparateUrl = "http://callback.jxc4.com/lakalaCallback/separate" // 消息通知地址(分账申请/撤回/退回 回调)
BillProdCallbackUrl = "http://callback.jxc4.com/lakalaCallback/ewalletWithdrawD1" // 账户D1提现回调
OrderStatusCallback = "http://callback.jxc4.com/lakalaCallback/orderStatus" // 收银台订单通知(订单状态)
PayStatusCallback = "http://callback.jxc4.com/lakalaCallback/payStatus" // 主扫支付状态通知
)

View File

@@ -0,0 +1,214 @@
package lakala
import (
"fmt"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
"go.uber.org/zap"
"testing"
)
var (
api *API
sugarLogger *zap.SugaredLogger
)
func init() {
logger, _ := zap.NewDevelopment()
sugarLogger = logger.Sugar()
baseapi.Init(sugarLogger)
incomingToken := "45e36fcc-7fe6-4235-9b15-9de16663be5f"
modifiedToken := "73184b9f-87d7-426a-9474-d8b8c98b037c"
//incomingExpire := time.Now().Unix()+42896
orgCode := "200669"
api = New(AppID, SerialNo, SM4Key, ClientID, ClientSecret, incomingToken, modifiedToken, orgCode)
}
// TestIncomingTest 获取创建token
func TestIncomingTest(t *testing.T) {
incomingToken, expires, err := api.IncomingToken()
fmt.Println(incomingToken, expires, err)
}
// TestModifiedToken 获取更新token
func TestModifiedToken(t *testing.T) {
modifiedToken, modifiedExpires, err := api.ModifiedToken(UserName, Password)
fmt.Println(modifiedToken, modifiedExpires, err)
}
// TestOrganization 获取城市组织代码
func TestOrganization(t *testing.T) {
// 6510 成都市 6515 金牛
organizationList, err := api.GetOrganizationCode("6510")
if err != nil {
globals.SugarLogger.Debugf("err := %v", err)
} else {
globals.SugarLogger.Debugf("organizationList := %s", utils.Format4Output(organizationList, false))
}
}
// 获取银行列表
func TestBankList(t *testing.T) {
bankList, err := api.GetBankList("6510", "")
if err != nil {
globals.SugarLogger.Debugf("err := %v", err)
} else {
globals.SugarLogger.Debugf("bankList := %s", utils.Format4Output(bankList, false))
}
}
// TestGetCustomAndCategoryList 获取门店商户类别
func TestGetCustomAndCategoryList(t *testing.T) {
businessScene, err := api.GetMerchantMcc("2", "")
if err != nil {
globals.SugarLogger.Debugf("err := %v", err)
} else {
globals.SugarLogger.Debugf("businessScene := %s", utils.Format4Output(businessScene, false))
}
// 获取餐饮小分类
businessSceneCategory, err := api.GetMerchantMcc("", "11000")
if err != nil {
globals.SugarLogger.Debugf("err := %v", err)
} else {
globals.SugarLogger.Debugf("businessSceneCategory := %s", utils.Format4Output(businessSceneCategory, false))
}
}
func TestUploadImg(t *testing.T) {
filePath := "https://image.jxc4.com/image/7325d87faa6179e0d86dad9ae27cbbc1.jpg"
data, err := api.FileUpload(filePath, IdCardFront, "0", "false")
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
globals.SugarLogger.Debugf("------%s", utils.Format4Output(data, false))
}
}
func TestIncoming(t *testing.T) {
param := &MerchantIncomingReq{
LarIdType: "01",
Attchments: []AttchmentsList{
{
Id: "merchant/null/20231227172245221010CHECKSTAND_IMG.png",
Type: "CHECKSTAND_IMG",
},
{
Id: "merchant/null/20231227172251776083SHOP_OUTSIDE_IMG.png",
Type: "SHOP_OUTSIDE_IMG",
},
},
LicenseNo: "92450202MA5MWYQK23",
AccountName: "徐丽",
CityCode: "6140",
UserNo: "20000101",
Latitude: "114.034257",
BizContent: BizContentParam{
ActivityId: "37",
Fees: []Fees{
{FeeCode: "WECHAT", FeeValue: "0.60"},
{FeeCode: "ALIPAY", FeeValue: "0.60"},
{FeeCode: "SCAN_PAY", FeeValue: "0.60"},
{TopFee: "20", FeeCode: "DEBIT_CARD", FeeValue: "0.38"},
{FeeCode: "CREDIT_CARD", FeeValue: "0.6"},
{TopFee: "20", FeeCode: "UNIONPAY_WALLET_DEBIT_FEE", FeeValue: "0.38"},
{FeeCode: "UNIONPAY_WALLET_CREDIT_FEE", FeeValue: "0.6"},
},
Mcc: "11002",
TermNum: "1",
},
MerName: "烟酒行批发24小时",
OpenningBankName: "中国农业银行广西柳州市柳南支行营业室",
SettleCityName: "柳州市",
Source: "H5",
LicenseDtEnd: "9999-12-31",
SettleProvinceCode: "45",
Longtude: "22.663572",
AccountNo: "6228480850854176714",
LarName: "徐哈哈",
LarIdCardStart: "2015-01-16",
Email: "2804711849@qq.com",
OpenningBankCode: "103614010818",
ContactMobile: "18276770550",
AccountIdDtStart: "2015-01-16",
LarIdCard: "460027200111297612",
SettleCityCode: "6140",
ProvinceCode: "6100",
ContactName: "徐哈哈",
BusiCode: "WECHAT_PAY",
AccountType: "58",
LicenseName: "烟酒行批发24小时",
MerAddr: "柳州市解放南路金鱼巷1号花旗壹号楼15-10",
LicenseDtStart: "2017-11-21",
LarIdCardEnd: "2035-01-16",
CountyCode: "986140",
AccountIdDtEnd: "2035-01-16",
MerRegName: "烟酒行批发24小时",
AccountIdCard: "460027200111297612",
SettleProvinceName: "广西",
MerType: "TP_PERSONAL",
ClearingBankCode: "103100000026",
BusinessContent: "烟酒行批发24小时",
SettleType: "D1",
}
t.Log(utils.Format4Output(param, false))
api.MerchantIncoming(param)
}
func TestGetMerchantInfo(t *testing.T) {
api.GetMerchantInfo("100139367")
}
// TestFeeQuery 商户费率信息查询
func TestFeeQuery(t *testing.T) {
fees, err := api.MerchantFeeQuery("100139367", "")
if err != nil {
t.Log(err)
} else {
globals.SugarLogger.Debugf("-----fees := %s", utils.Format4Output(fees, false))
}
}
// TestMerchantFeeChange 商户费率变更
func TestMerchantFeeChange(t *testing.T) {
param := &FeeChangeReq{
Attachments: nil,
Fees: []FeeInfoDto{{
Fee: 0.38,
FeeType: "UNIONPAY_WALLET_DEBIT_FEE",
TopFee: 20,
}},
ProductCode: "",
SettleType: "",
WithdrawalType: "",
SettlementType: "",
RegularSettlementTime: "",
}
api.MerchantFeeChange(param, "100139367")
}
// TestQueryMerchantReviewStatus 获取门店审核状态
func TestQueryMerchantReviewStatus(t *testing.T) {
api.QueryMerchantReviewStatus("11111")
}
// TestCheckImgIsSupplement 检查门店需要补充的图片
func TestCheckImgIsSupplement(t *testing.T) {
api.CheckImgIsSupplement("100139367")
}
// TestGetMerchantReportStatus 商户报备查询
func TestGetMerchantReportStatus(t *testing.T) {
api.GetMerchantReportStatus("231464", "22203211", "82212107011011G")
}
// TestGetMerchantTerminal 设备终端报备查询
func TestGetMerchantTerminal(t *testing.T) {
api.GetMerchantTerminal("231464", "22203211", "82212107011011G", "47884567")
}
func TestUnionPayMerInfo(t *testing.T) {
api.UnionPayMerInfo("刘磊", "511324199308263974")
}

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgIGAZcPay8zMA0GCSqGSIb3DQEBBQUAMGAxFDASBgNVBAMM
C0xBS0FMQS1MQU9QMQswCQYDVQQGEwJDTjEXMBUGA1UECgwOTGFrYWxhIENvLixM
dGQxDzANBgNVBAsMBkxLTC1ZRjERMA8GA1UEBwwIc2hhbmdoYWkwHhcNMjUwNTI3
MDE0NjEyWhcNMzUwNTI3MDE0NjEyWjBgMRQwEgYDVQQDDAtMQUtBTEEtTEFPUDEL
MAkGA1UEBhMCQ04xFzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMQ8wDQYDVQQLDAZM
S0wtWUYxETAPBgNVBAcMCHNoYW5naGFpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEApNEV8dtAfwBaaxa+DhdBE+zpcrwUcjnPmT9LqwgK2f4Ts9QdHjhj
+A+w3Y8NWIHGHuvD+XUJfV/4KQ0tFmvhHXcH18HzNEqB1QDinjiNxcEFh1lXm7BE
sWRTfI5bVZsnN0D0oIuAo/Bilw7jM5UmsdIXXs4Mv3HV45gRzNaY1OYJU5pRhF+0
BqPuzfX93oPlFW2wZ/DZR2hCs6ZZsHlKLnSTY0vJSWhnPHoWH1sYjNtAESQEDbrV
fBVwKgpjjVuZ1EM/UvQ46llktcAz5YypRcsV8jlMmhUzWJ7z3LCw46PPWAn5nH4p
cF3j9dTf0AKZGnx6bnpeWy4NDPip6PKEoQIDAQABo2AwXjAPBgNVHRMECDAGAQH/
AgEAMB8GA1UdIwQYMBaAFP5WWOX3fRBb3TEz1QYBdgsbsh58MB0GA1UdDgQWBBT+
Vljl930QW90xM9UGAXYLG7IefDALBgNVHQ8EBAMCBsAwDQYJKoZIhvcNAQEFBQAD
ggEBACD6h2hLyfeOGV1NyUkvzI1pjLau5oPNYpU0ULeMQ00a6cQI+scaE8wApsx/
pH0rEcUNle7GoH5lqGqKnmTuJkBpQHnIoLlKsHq50DRPw02nlF8GR1iu/m8giaoH
hKxr6oB2l6HN5P5oYoxr4Vk20Rcd8BxQDYJXZAUfqK2n4QKd/Lj7+xwudAk+Os0Y
j+CsdkuFPzeE0W31QL3GMWl7f+lxMqPKVA1IWZ5HGUl18M7nJyVgK7+bY2DlZhyA
CSSB891ETo+Nh+KwR57c8LYaN59JFOkgrFkA1JijzuQ023q4sd0IFoPVEbW2LqK0
T/YxOCpqc7ciYvkPfrECfXagPH0=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCk0RXx20B/AFpr
Fr4OF0ET7OlyvBRyOc+ZP0urCArZ/hOz1B0eOGP4D7Ddjw1YgcYe68P5dQl9X/gp
DS0Wa+EddwfXwfM0SoHVAOKeOI3FwQWHWVebsESxZFN8jltVmyc3QPSgi4Cj8GKX
DuMzlSax0hdezgy/cdXjmBHM1pjU5glTmlGEX7QGo+7N9f3eg+UVbbBn8NlHaEKz
plmweUoudJNjS8lJaGc8ehYfWxiM20ARJAQNutV8FXAqCmONW5nUQz9S9DjqWWS1
wDPljKlFyxXyOUyaFTNYnvPcsLDjo89YCfmcfilwXeP11N/QApkafHpuel5bLg0M
+Kno8oShAgMBAAECggEALEL6Ybk/2Nt/bMLux1n3YCJ/jxBzbTmZRs54w7WlNGXH
ZMPSDguWzUdpeBayvtIbIrKuLo//vGvJeTzQnvTZv8/3iznK1oAr3cgfE96cND9h
/LdBj84GpJ0MzqZsYNEJ9wy6pWLRaTVlRKv62B92BMsm+47aXY90oWp1XU1EPegZ
UadGMYUv8c3rCXXJYjIlJFm8i65y/DdklvKs3tG8t+LyIdNeVdPNHqYMEFBHOvn1
1wUt8sstWp1NrmkfnkE3jTxK80qu+VwQtoBjGOdh7RCBn2AvtWwcl5GUC+oxxh5S
bbljH03u/YklmOlojjWkfWS/SxuM3CO8ETxMSoK/AQKBgQDxiz4vRelKWajj44jG
HRaKv/fBOM+AzkGHZ1mrP3pE+JGfnRZoMnYChTJ3rYb+ZKxftyF50/O7xosqvpS5
f6fNQ+h2QzbL/o1uPD38/Ty14HyWCV5QKGv3TYRqUcG8jYXCHupydHZtKEX2h4Ws
pL/osVvMNemseMEynjVCx1UeMwKBgQCurkkrMUOoLXooXWHF1fjh61p1nyUWsGOx
x8Wk4Lm7h1iRB0rJruL9lQXVgiwyMmfh92fvz8EMIHCM7euviBrQE8okh4M18Epr
f8a6uouaqXXZguUBtxMYnYQGyVR1B6/Y6sFC10IswTncLdu+7WGaQeUmiwaSWryP
MIDg+zqV2wKBgFofz0sKNdqVC6xEKLNrBQ8uQ34n+VyhGNgx2sZHwBJeAM/iaArm
0RttoYAAEj93Rs3L4cS4LdghY6nGRG3WUMEJFoKR369Lwm+gMKzlvDJMmY/N3Q/h
lS9IECEvci8tSvw8VtPv2oQuI7SxqlHZgvWKv6q5bv/4anW9jDfncj37AoGAf3P3
Oyak4O7dtNn93uWyxNR+mlfWLenhs/O5SAYYPrYQbzFM5j9OrAuxyAlEyhNxLLTi
B14k0v5QYOOwFdFPDweBdInTuOVsx2bhz5kRB3Yh4OTaxxeXPVyg2nrHvuQu8CzJ
ekWpqRILb5WeQn7dujneQvMphlviPO/8+SsVogUCgYA9MTpa0TyI5k5kHM/S2GHW
YSwFwN7kd8meI0+2jPUKs/SFdTuYdnprl18TOT7c4nw0bShgbAA+D+zCweUKa3Yu
qk915Dtg5oVuWI7ueUwJkDy4ITOoU38yMiAfXS+mRs9t37EbRVGMEsTrplKBy8OS
wmorJON4jA4sZ5SG0xG5xQ==
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApNEV8dtAfwBaaxa+DhdB
E+zpcrwUcjnPmT9LqwgK2f4Ts9QdHjhj+A+w3Y8NWIHGHuvD+XUJfV/4KQ0tFmvh
HXcH18HzNEqB1QDinjiNxcEFh1lXm7BEsWRTfI5bVZsnN0D0oIuAo/Bilw7jM5Um
sdIXXs4Mv3HV45gRzNaY1OYJU5pRhF+0BqPuzfX93oPlFW2wZ/DZR2hCs6ZZsHlK
LnSTY0vJSWhnPHoWH1sYjNtAESQEDbrVfBVwKgpjjVuZ1EM/UvQ46llktcAz5Yyp
RcsV8jlMmhUzWJ7z3LCw46PPWAn5nH4pcF3j9dTf0AKZGnx6bnpeWy4NDPip6PKE
oQIDAQAB
-----END PUBLIC KEY-----

View File

@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYTCCAkmgAwIBAgIJAN+6gZTEG4TPMA0GCSqGSIb3DQEBCwUAMEkxCzAJBgNV
BAYTAlVTMREwDwYDVQQIEwhzaGFuZ2hhaTERMA8GA1UEBxMIc2hhbmdoYWkxFDAS
BgNVBAMUC2xha2FsYV8yMDIxMB4XDTIxMDYxODA3MjEzNFoXDTMxMDYxOTA3MjEz
NFowSTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCHNoYW5naGFpMREwDwYDVQQHEwhz
aGFuZ2hhaTEUMBIGA1UEAxQLbGFrYWxhXzIwMjEwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDvDBZyHUDndAGxrIcsCV2njhNO3vCEZotTaWYSYwtDvkcA
b1EjsBFabXZaKigpqFXk5XXNI3NIHP9M8XKzIgGvc65NpLAfRjVql8JiTvLyYd1g
IUcOXMInabu+oX7dQSI1mS8XzqaoVRhDZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si
+hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbWdhZ+NHwitnQwAJTLBFvfk28INM39G7XO
sXdVLfsooFdglVTOHpNuRiQAj9gShCCNrpGsNQxDiJIxE43qRsNsRwigyo6DPJk/
klgDJa417E2wgP8VrwiXparO4FMzOGK15quuoD7DAgMBAAGjTDBKMAkGA1UdEwQC
MAAwEQYJYIZIAYb4QgEBBAQDAgTwMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggr
BgEFBQcDAgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAI21YYAlH+Pc1ISv
nbQrGqL8suGL0Hh/8hGaFfrJEJEKr9OeC8jElUhck2MTmfu/Y1lB7r8RBrhGPXi4
kTXmB6ADs/9+ezNW3WXyFj7fhs3JcZ3mo33T9wyQySDKd//JrEtrTsc/s2PZ602y
qNmPomXSzjrlugaMyC7LI9sR44mc7sQnchjHoxrQFD5/usTFW72UQfYCORsQWYMt
0KKEyAcpRL51RE3xbX1WDtduFYGP62PbwLAn2nCL/j1wlF5hltWj7sditWqKgso5
F8BTffn2Bb0RdsNxqwMy1cTPrWLeXVOqMDu3ge7hvoav8lZKTjk5Kmqhs7wNAQXK
mg9qSwo=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDvDBZyHUDndAGx
rIcsCV2njhNO3vCEZotTaWYSYwtDvkcAb1EjsBFabXZaKigpqFXk5XXNI3NIHP9M
8XKzIgGvc65NpLAfRjVql8JiTvLyYd1gIUcOXMInabu+oX7dQSI1mS8XzqaoVRhD
ZQWhXcJW9bxMulgnzvk0Ggw07AjGF7si+hP/Va8SJmN7EJwfQq6TpSxR+WdIHpbW
dhZ+NHwitnQwAJTLBFvfk28INM39G7XOsXdVLfsooFdglVTOHpNuRiQAj9gShCCN
rpGsNQxDiJIxE43qRsNsRwigyo6DPJk/klgDJa417E2wgP8VrwiXparO4FMzOGK1
5quuoD7DAgMBAAECggEBANhmWOt1EAx3OBFf3f4/fEjylQgRSiqRqg8Ymw6KGuh4
mE4Md6eW/B6geUOmZjVP7nIIR1wte28M0REWgn8nid8LGf+v1sB5DmIwgAf+8G/7
qCwd8/VMg3aqgQtRp0ckb5OV2Mv0h2pbnltkWHR8LDIMwymyh5uCApbn/aTrCAZK
NXcPOyAn9tM8Bu3FHk3Pf24Er3SN+bnGxgpzDrFjsDSHjDFT9UMIc2WdA3tuMv9X
3DDn0bRCsHnsIw3WrwY6HQ8mumdbURk+2Ey3eRFfMYxyS96kOgBC2hqZOlDwVPAK
TPtS4hoq+cQ0sRaJQ4T0UALJrBVHa+EESgRaTvrXqAECgYEA+WKmy9hcvp6IWZlk
9Q1JZ+dgIVxrO65zylK2FnD1/vcTx2JMn73WKtQb6vdvTuk+Ruv9hY9PEsf7S8gH
STTmzHOUgo5x0F8yCxXFnfji2juoUnDdpkjtQK5KySDcpQb5kcCJWEVi9v+zObM0
Zr1Nu5/NreE8EqUl3+7MtHOu1TMCgYEA9WM9P6m4frHPW7h4gs/GISA9LuOdtjLv
AtgCK4cW2mhtGNAMttD8zOBQrRuafcbFAyU9de6nhGwetOhkW9YSV+xRNa7HWTeI
RgXJuJBrluq5e1QGTIwZU/GujpNaR4Qiu0B8TodM/FME7htsyxjmCwEfT6SDYlke
MzTbMa9Q0DECgYBqsR/2+dvD2YMwAgZFKKgNAdoIq8dcwyfamUQ5mZ5EtGQL2yw4
8zibHh/LiIxgUD1Kjk/qQgNsX45NP4iOc0mCkrgomtRqdy+rumbPTNmQ0BEVJCBP
scd+8pIgNiTvnWpMRvj7gMP0NDTzLI3wnnCRIq8WAtR2jZ0Ejt+ZHBziLQKBgQDi
bEe/zqNmhDuJrpXEXmO7fTv3YB/OVwEj5p1Z/LSho2nHU3Hn3r7lbLYEhUvwctCn
Ll2fzC7Wic1rsGOqOcWDS5NDrZpUQGGF+yE/JEOiZcPwgH+vcjaMtp0TAfRzuQEz
NzV8YGwxB4mtC7E/ViIuVULHAk4ZGZI8PbFkDxjKgQKBgG8jEuLTI1tsP3kyaF3j
Aylnw7SkBc4gfe9knsYlw44YlrDSKr8AOp/zSgwvMYvqT+fygaJ3yf9uIBdrIilq
CHKXccZ9uA/bT5JfIi6jbg3EoE9YhB0+1aGAS1O2dBvUiD8tJ+BjAT4OB0UDpmM6
QsFLQgFyXgvDnzr/o+hQJelW
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEMTCCAxmgAwIBAgIGAXRTgcMnMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT
AkNOMRAwDgYDVQQIDAdCZWlKaW5nMRAwDgYDVQQHDAdCZWlKaW5nMRcwFQYDVQQK
DA5MYWthbGEgQ28uLEx0ZDEqMCgGA1UEAwwhTGFrYWxhIE9yZ2FuaXphdGlvbiBW
YWxpZGF0aW9uIENBMB4XDTIwMTAxMDA1MjQxNFoXDTMwMTAwODA1MjQxNFowZTEL
MAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaUppbmcxEDAOBgNVBAcMB0JlaUppbmcx
FzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMRkwFwYDVQQDDBBBUElHVy5MQUtBTEEu
Q09NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1zHL54HiI8d2sLJ
lwoQji3/ln0nsvfZ/XVpOjuB+1YR6/0LdxEDMC/hxI6iH2Rm5MjwWz3dmN/6BZeI
gwGeTOWJUZFARo8UduKrlhC6gWMRpAiiGC8wA8stikc5gYB+UeFVZi/aJ0WN0cpP
JYCvPBhxhMvhVDnd4hNohnR1L7k0ypuWg0YwGjC25FaNAEFBYP9EYUyCJjE//9Z7
sMzHR9SJYCqqo6r9bOH9G6sWKuEp+osuAh+kJIxJMHfipw7w3tEcWG0hce9u/el4
cYJtg8/PPMVoccKmeCzMvarr7jdKP4lenJbtwlgyfs+JgNu60KMUJH8RS72wC9NY
uFz09wIDAQABo4HVMIHSMIGSBgNVHSMEgYowgYeAFCnH4DkZPR6CZxRn/kIqVsMo
dJHpoWekZTBjMQswCQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpSmluZzEQMA4GA1UE
BwwHQmVpSmluZzEXMBUGA1UECgwOTGFrYWxhIENvLixMdGQxFzAVBgNVBAMMDkxh
a2FsYSBSb290IENBggYBaiUALIowHQYDVR0OBBYEFJ2Kx9YZfmWpkKFnC33C0r5D
K3rFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA
A4IBAQBZoeU0XyH9O0LGF9R+JyGwfU/O5amoB97VeM+5n9v2z8OCiIJ8eXVGKN9L
tl9QkpTEanYwK30KkpHcJP1xfVkhPi/cCMgfTWQ5eKYC7Zm16zk7n4CP6IIgZIqm
TVGsIGKk8RzWseyWPB3lfqMDR52V1tdA1S8lJ7a2Xnpt5M2jkDXoArl3SVSwCb4D
AmThYhak48M++fUJNYII9JBGRdRGbfJ2GSFdPXgesUL2CwlReQwbW4GZkYGOg9LK
CNPK6XShlNdvgPv0CCR08KCYRwC3HZ0y1F0NjaKzYdGNPrvOq9lA495ONZCvzYDo
gmsu/kd6eqxTs/JwdaIYr4sCMg8Z
-----END CERTIFICATE-----

View File

@@ -2,7 +2,6 @@ package mtwmapi
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
)
const (
@@ -60,9 +59,6 @@ func (a *API) GetStoreBillList(param *Bill) (map[string]*SettleOrderList, int64,
if !ok {
settle = &SettleOrderList{OrderId: v.WmOrderViewId}
}
if v.WmOrderViewId == "2001521861299113073" {
globals.SugarLogger.Debugf("------%s:%s", v.WmOrderViewId, utils.Format4Output(v, false))
}
switch v.BillChargeType {
case BillChargeTypeOrder: // 平台结算
settle.PlatformSettlement = v.SettleAmount

View File

@@ -9,9 +9,9 @@ import (
func TestBillList(t *testing.T) {
now := time.Now()
from := time.Date(now.Year(), now.Month(), now.Day()-2, 0, 0, 0, 0, time.Local)
to := time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 59, time.Local)
to := time.Date(now.Year(), now.Month(), now.Day()-2, 23, 59, 59, 59, time.Local)
param := &Bill{
AppPoiCode: "20046303",
AppPoiCode: "7290541",
StartDate: from.Unix(),
EndDate: to.Unix(),
Offset: 0,

View File

@@ -12,7 +12,7 @@ import (
)
func TestCommentQuery(t *testing.T) {
result, err := api.CommentQuery("27674533", "20250420", "20250514", 40, 20, CommentReplyStatusAll)
result, err := api.CommentQuery("27674533", "20250426", "20250514", 0, 0, CommentReplyStatusAll)
if err != nil {
t.Fatal(err)
}

View File

@@ -20,13 +20,13 @@ func init() {
baseapi.Init(sugarLogger)
// 菜市
api = New("589", "a81eb3df418d83d6a1a4b7c572156d2f", "", "")
//api = New("589", "a81eb3df418d83d6a1a4b7c572156d2f", "", "")
// 果园
//api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "")
//商超
//api = New("5873", "41c479790a76f86326f89e8048964739", "", "token_n49KrTnbe-Qatd-80sFOnQ")
api = New("5873", "41c479790a76f86326f89e8048964739", "", "token_oku5J6-UzKWdNwcNdXNOKA")
//cookieStr := `
// acctId=57396785; token=0bWbK5VbK50E2BmIhIH2zHB-am_y7mB37yXHm6RLZWx4*; wmPoiId=-1;
//`

View File

@@ -144,13 +144,16 @@ func TestOrderGetRiderInfoPhoneNumber(t *testing.T) {
}
func TestGetOrderRefundDetail(t *testing.T) {
result, err := api.GetOrderRefundDetail(301135342863962437, 0)
result, err := api.GetOrderRefundDetail(3901636712926079606, 0)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
}
func Test111(t *testing.T) {
fmt.Println(utils.Float64TwoInt64((6.32 / 15.8) * float64(950)))
}
func TestGetOrderRefundDetail2(t *testing.T) {
result, err := api.GetOrderRefundDetail(601112850243823799, 0)
if err != nil {

View File

@@ -189,7 +189,7 @@ func TestRetailListCase(t *testing.T) {
}
func TestRetailGet(t *testing.T) {
orderDetail, _ := api.OrderGetOrderDetail(4101393090068943089, false)
orderDetail, _ := api.OrderGetOrderDetail(3801609511466390200, false)
if addressFee, ok := orderDetail["address_change_fee"]; ok {
fmt.Println(addressFee)
}
@@ -201,6 +201,13 @@ func TestRetailGet(t *testing.T) {
//t.Log(utils.Format4Output(result, false))
}
func TestCCC(t *testing.T) {
data := "[\"13812345678_1236\",\"13812345678_3456\"]"
phones := make([]string, 0, 0)
json.Unmarshal([]byte(data), &phones)
fmt.Println(data)
}
func TestRetailGetSpTagIds(t *testing.T) {
result, err := api.RetailGetSpTagIds()
if err != nil {

View File

@@ -141,11 +141,16 @@ func AccessPlatformAPIWithRetry(client *http.Client, handleRequest func() *http.
continue
}
}
if bodyData, err := ioutil.ReadAll(response.Body); err == nil {
bodyData, err := ioutil.ReadAll(response.Body)
if err == nil {
baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s HTTP code is:%d, url:%v, response:%s", trackInfo, response.StatusCode, request.URL, string(bodyData))
} else {
baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry:%s ioutil.ReadAll failed, HTTP code is:%d, url:%v, error:%v", trackInfo, response.StatusCode, request.URL, err)
}
if bodyData != nil {
return errors.New(string(bodyData))
}
return ErrHTTPCodeIsNot200
}
var (

View File

@@ -92,7 +92,7 @@ func (a *API) ShopUpdateInfo(storeID, sTime, eTime string) error {
return err
}
if resp.ApiResult.ErrMsg != nil {
return fmt.Errorf("ShopUpdateInfo:requestId:" + resp.RequestId + "msg:" + *resp.ApiResult.ErrMsg)
return fmt.Errorf("msg:" + *resp.ApiResult.ErrMsg)
}
return nil
}

View File

@@ -9,7 +9,7 @@ import (
)
// 京西速食(蔬菜)
var token1 = `{"access_token":"jqucw88uv31j7t4nq1hehos0000yhugi-11","expires_in":1747057558,"scope":"SCOPE","shop_id":57939570,"shop_name":"京西菜市","refresh_token":"fh87prlznn1j7t4nq1hehos0000yhugi-12","authority_id":""}`
var token1 = `{"access_token":"8vz7w9072y1j7t4nq1hehos0000yhugi-11","expires_in":1748863872,"scope":"SCOPE","shop_id":57939570,"shop_name":"京西菜市","refresh_token":"1wm2s8x5c91j7t4nq1hehos0000yhugi-12","authority_id":""}`
// 美好菜市
//var token1 = `{"access_token":"9a315a03-c737-4a82-ae52-c9a6ce827007","expires_in":1699490747,"scope":"SCOPE","shop_id":68032645,"shop_name":"美好菜市","refresh_token":"8334c006-5301-4d25-911b-4d8cc7b70ebb","authority_id":""}`

View File

@@ -8,7 +8,7 @@ import (
)
func TestBillDetail(t *testing.T) {
orderDetail, err := a.GetTiktokOrderDetail("6930445286770611595")
orderDetail, err := a.GetTiktokOrderDetail("6942903863479899501")
if err != nil {
fmt.Println(err)
}
@@ -17,7 +17,6 @@ func TestBillDetail(t *testing.T) {
for _, v := range orderDetail.SkuOrderList {
childrenOrderList = append(childrenOrderList, v.OrderId)
}
childrenOrderList = append(childrenOrderList, "6930445286770611595")
date, datae, err := a.GetSettleBillDetailV3(&order_getSettleBillDetailV3_request.OrderGetSettleBillDetailV3Param{
Size: 20,

View File

@@ -16,10 +16,10 @@ const (
sepcAction2 = "h5unionpay/unionorder"
sigKey = "sign"
PayTypeWxXcx = "W06"
PayTypeWxCode = "W01"
PayTypeZfbApp = "A03"
PayTypeZfbQrcode = "A01"
PayTypeWxXcx = "W06" // 小程序支付
PayTypeWxCode = "W01" // 微信支付
PayTypeZfbApp = "A03" // 支付宝小程序
PayTypeZfbQrcode = "A01" // 支付宝支付
PayTypeZfbJS = "A02"
PayTypeH5 = "H5"

View File

@@ -308,6 +308,9 @@ func Time2Str(t time.Time) string {
func Time2TimeStr(t time.Time) string {
return t.Format("15:04:05")
}
func Time2TimeStrByFormat(t time.Time, format string) string {
return t.Format(format)
}
func Time2Date(t time.Time) time.Time {
year, month, day := t.Date()