diff --git a/platformapi/ebaiapi/order_test.go b/platformapi/ebaiapi/order_test.go index 810acb9a..b3dcb9b2 100644 --- a/platformapi/ebaiapi/order_test.go +++ b/platformapi/ebaiapi/order_test.go @@ -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{}) diff --git a/platformapi/ebaiapi/shop_sku_test.go b/platformapi/ebaiapi/shop_sku_test.go index ecf8e362..0a577425 100644 --- a/platformapi/ebaiapi/shop_sku_test.go +++ b/platformapi/ebaiapi/shop_sku_test.go @@ -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) } diff --git a/platformapi/ebaiapi/shop_test.go b/platformapi/ebaiapi/shop_test.go index 778ac399..6e7fe1a2 100644 --- a/platformapi/ebaiapi/shop_test.go +++ b/platformapi/ebaiapi/shop_test.go @@ -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) { diff --git a/platformapi/jdapi/jdapi_test.go b/platformapi/jdapi/jdapi_test.go index 801bd309..2156d185 100644 --- a/platformapi/jdapi/jdapi_test.go +++ b/platformapi/jdapi/jdapi_test.go @@ -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 diff --git a/platformapi/jdapi/order_test.go b/platformapi/jdapi/order_test.go index 4c9cc289..caf8db99 100644 --- a/platformapi/jdapi/order_test.go +++ b/platformapi/jdapi/order_test.go @@ -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 { diff --git a/platformapi/lakala/lakala_api.go b/platformapi/lakala/lakala_api.go new file mode 100644 index 00000000..62876465 --- /dev/null +++ b/platformapi/lakala/lakala_api.go @@ -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) + } +} diff --git a/platformapi/lakala/lakala_bill.go b/platformapi/lakala/lakala_bill.go new file mode 100644 index 00000000..ce93651a --- /dev/null +++ b/platformapi/lakala/lakala_bill.go @@ -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 +} diff --git a/platformapi/lakala/lakala_bill_model.go b/platformapi/lakala/lakala_bill_model.go new file mode 100644 index 00000000..654c5c29 --- /dev/null +++ b/platformapi/lakala/lakala_bill_model.go @@ -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) 提款模式02,03生效 + 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"` // 留存金额(单位:元) 否 +} diff --git a/platformapi/lakala/lakala_bill_test.go b/platformapi/lakala/lakala_bill_test.go new file mode 100644 index 00000000..0e8ded89 --- /dev/null +++ b/platformapi/lakala/lakala_bill_test.go @@ -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")) +} diff --git a/platformapi/lakala/lakala_callback_model.go b/platformapi/lakala/lakala_callback_model.go new file mode 100644 index 00000000..31f2f9f7 --- /dev/null +++ b/platformapi/lakala/lakala_callback_model.go @@ -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单元为Object,Object对象包含如下字段 ,按交易完成时间逆序排列 + 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 +} diff --git a/platformapi/lakala/lakala_incoming.go b/platformapi/lakala/lakala_incoming.go new file mode 100644 index 00000000..ae631f37 --- /dev/null +++ b/platformapi/lakala/lakala_incoming.go @@ -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 +} diff --git a/platformapi/lakala/lakala_incoming_model.go b/platformapi/lakala/lakala_incoming_model.go new file mode 100644 index 00000000..ba422a41 --- /dev/null +++ b/platformapi/lakala/lakala_incoming_model.go @@ -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 + ActiveNoVoList []struct { + BusiTypeCode string `json:"busiTypeCode"` // 业务类别码 String + TermNo string `json:"termNo"` // 终端号 String + ActiveNo string `json:"activeNo"` // 终端激活码 String + } `json:"activeNoVoList"` //激活码 List +} + +// 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"` // 共共计查询到的商户记录数量 +} diff --git a/platformapi/lakala/lakala_order.go b/platformapi/lakala/lakala_order.go new file mode 100644 index 00000000..a403363e --- /dev/null +++ b/platformapi/lakala/lakala_order.go @@ -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 + +} diff --git a/platformapi/lakala/lakala_order_model.go b/platformapi/lakala/lakala_order_model.go new file mode 100644 index 00000000..ae3f09fe --- /dev/null +++ b/platformapi/lakala/lakala_order_model.go @@ -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:银联云闪付 CARD:POS刷卡交易 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单元为Object,Object对象包含如下字段 ,按交易完成时间逆序排列 +} + +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 20200326,posp接口必填 + 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"` // 账户端优惠金额 +} diff --git a/platformapi/lakala/lakala_order_test.go b/platformapi/lakala/lakala_order_test.go new file mode 100644 index 00000000..e7c09cfd --- /dev/null +++ b/platformapi/lakala/lakala_order_test.go @@ -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) +} diff --git a/platformapi/lakala/lakala_pay.go b/platformapi/lakala/lakala_pay.go new file mode 100644 index 00000000..2056d09f --- /dev/null +++ b/platformapi/lakala/lakala_pay.go @@ -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)) + } + +} diff --git a/platformapi/lakala/lakala_pay_model.go b/platformapi/lakala/lakala_pay_model.go new file mode 100644 index 00000000..3f97d6f5 --- /dev/null +++ b/platformapi/lakala/lakala_pay_model.go @@ -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:NATIVE((ALIPAY,云闪付支持,京东白条分期)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) 微信分配的子商户公众账号ID,sub_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:未知 +} diff --git a/platformapi/lakala/lakala_pay_test.go b/platformapi/lakala/lakala_pay_test.go new file mode 100644 index 00000000..70bb7d81 --- /dev/null +++ b/platformapi/lakala/lakala_pay_test.go @@ -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: "", + }) +} diff --git a/platformapi/lakala/lakala_separate_accounts.go b/platformapi/lakala/lakala_separate_accounts.go new file mode 100644 index 00000000..ef892b52 --- /dev/null +++ b/platformapi/lakala/lakala_separate_accounts.go @@ -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 +} diff --git a/platformapi/lakala/lakala_separate_accounts_model.go b/platformapi/lakala/lakala_separate_accounts_model.go new file mode 100644 index 00000000..b5d410fc --- /dev/null +++ b/platformapi/lakala/lakala_separate_accounts_model.go @@ -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"` // 拉卡拉对账单流水号 +} diff --git a/platformapi/lakala/lakala_separate_accounts_test.go b/platformapi/lakala/lakala_separate_accounts_test.go new file mode 100644 index 00000000..9dfe99c8 --- /dev/null +++ b/platformapi/lakala/lakala_separate_accounts_test.go @@ -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") +} diff --git a/platformapi/lakala/lakala_token.go b/platformapi/lakala/lakala_token.go new file mode 100644 index 00000000..737386b1 --- /dev/null +++ b/platformapi/lakala/lakala_token.go @@ -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(), + } +} diff --git a/platformapi/lakala/lakala_token_model.go b/platformapi/lakala/lakala_token_model.go new file mode 100644 index 00000000..bdf60b13 --- /dev/null +++ b/platformapi/lakala/lakala_token_model.go @@ -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" // 主扫支付状态通知 +) diff --git a/platformapi/lakala/lakala_token_test.go b/platformapi/lakala/lakala_token_test.go new file mode 100644 index 00000000..bdbcdc5a --- /dev/null +++ b/platformapi/lakala/lakala_token_test.go @@ -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") +} diff --git a/platformapi/lakala/pem_file/api_cert.cer b/platformapi/lakala/pem_file/api_cert.cer new file mode 100644 index 00000000..a5b1bb56 --- /dev/null +++ b/platformapi/lakala/pem_file/api_cert.cer @@ -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----- diff --git a/platformapi/lakala/pem_file/api_private_key.pem b/platformapi/lakala/pem_file/api_private_key.pem new file mode 100644 index 00000000..ce2a95e8 --- /dev/null +++ b/platformapi/lakala/pem_file/api_private_key.pem @@ -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----- diff --git a/platformapi/lakala/pem_file/api_public_key.pem b/platformapi/lakala/pem_file/api_public_key.pem new file mode 100644 index 00000000..3b244adb --- /dev/null +++ b/platformapi/lakala/pem_file/api_public_key.pem @@ -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----- diff --git a/platformapi/lakala/test_pem_file/OP00000003_cert.cer b/platformapi/lakala/test_pem_file/OP00000003_cert.cer new file mode 100644 index 00000000..f85afd02 --- /dev/null +++ b/platformapi/lakala/test_pem_file/OP00000003_cert.cer @@ -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----- diff --git a/platformapi/lakala/test_pem_file/OP00000003_private_key.pem b/platformapi/lakala/test_pem_file/OP00000003_private_key.pem new file mode 100644 index 00000000..7d95886c --- /dev/null +++ b/platformapi/lakala/test_pem_file/OP00000003_private_key.pem @@ -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----- diff --git a/platformapi/lakala/test_pem_file/lkl-apigw-v2-verification.cer b/platformapi/lakala/test_pem_file/lkl-apigw-v2-verification.cer new file mode 100644 index 00000000..12723ebe --- /dev/null +++ b/platformapi/lakala/test_pem_file/lkl-apigw-v2-verification.cer @@ -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----- diff --git a/platformapi/mtwmapi/bill_list.go b/platformapi/mtwmapi/bill_list.go index c255a7d9..6bbd1b3c 100644 --- a/platformapi/mtwmapi/bill_list.go +++ b/platformapi/mtwmapi/bill_list.go @@ -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 diff --git a/platformapi/mtwmapi/bill_list_test.go b/platformapi/mtwmapi/bill_list_test.go index 994a0f55..9d3f24e2 100644 --- a/platformapi/mtwmapi/bill_list_test.go +++ b/platformapi/mtwmapi/bill_list_test.go @@ -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, diff --git a/platformapi/mtwmapi/comment_test.go b/platformapi/mtwmapi/comment_test.go index 64ccf6a4..326f926d 100644 --- a/platformapi/mtwmapi/comment_test.go +++ b/platformapi/mtwmapi/comment_test.go @@ -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) } diff --git a/platformapi/mtwmapi/mtwmapi_test.go b/platformapi/mtwmapi/mtwmapi_test.go index ffa2df47..763229dd 100644 --- a/platformapi/mtwmapi/mtwmapi_test.go +++ b/platformapi/mtwmapi/mtwmapi_test.go @@ -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; //` diff --git a/platformapi/mtwmapi/order_test.go b/platformapi/mtwmapi/order_test.go index 2bb7ae3e..ac07dd27 100644 --- a/platformapi/mtwmapi/order_test.go +++ b/platformapi/mtwmapi/order_test.go @@ -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 { diff --git a/platformapi/mtwmapi/retail_test.go b/platformapi/mtwmapi/retail_test.go index e3e14726..1fa78ae5 100644 --- a/platformapi/mtwmapi/retail_test.go +++ b/platformapi/mtwmapi/retail_test.go @@ -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 { diff --git a/platformapi/platformapi.go b/platformapi/platformapi.go index f1d92614..861680ab 100644 --- a/platformapi/platformapi.go +++ b/platformapi/platformapi.go @@ -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 ( diff --git a/platformapi/tao_vegetable/store.go b/platformapi/tao_vegetable/store.go index fa36cd9c..20f8a166 100644 --- a/platformapi/tao_vegetable/store.go +++ b/platformapi/tao_vegetable/store.go @@ -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 } diff --git a/platformapi/tiktok_shop/tiktok_api/afs_test.go b/platformapi/tiktok_shop/tiktok_api/afs_test.go index aefb1f79..7b042540 100644 --- a/platformapi/tiktok_shop/tiktok_api/afs_test.go +++ b/platformapi/tiktok_shop/tiktok_api/afs_test.go @@ -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":""}` diff --git a/platformapi/tiktok_shop/tiktok_api/settl_bill_detail_test.go b/platformapi/tiktok_shop/tiktok_api/settl_bill_detail_test.go index 3397e18d..b4dee0dc 100644 --- a/platformapi/tiktok_shop/tiktok_api/settl_bill_detail_test.go +++ b/platformapi/tiktok_shop/tiktok_api/settl_bill_detail_test.go @@ -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, diff --git a/platformapi/tonglianpayapi/tonglian_model.go b/platformapi/tonglianpayapi/tonglian_model.go index 1bf8b1ff..8d81b1ce 100644 --- a/platformapi/tonglianpayapi/tonglian_model.go +++ b/platformapi/tonglianpayapi/tonglian_model.go @@ -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" diff --git a/utils/typeconv.go b/utils/typeconv.go index 4efdb34a..02dea669 100644 --- a/utils/typeconv.go +++ b/utils/typeconv.go @@ -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()