This commit is contained in:
邹宗楠
2025-04-27 10:17:40 +08:00
parent cf38acc037
commit 1a5a3ffc29
14 changed files with 920 additions and 156 deletions

View File

@@ -3,8 +3,10 @@ package dadaapi
import (
"fmt"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"go.uber.org/zap"
"strings"
"testing"
)
@@ -194,3 +196,58 @@ func Test222222(t *testing.T) {
// }
// }
//}
func Test111(t *testing.T) {
SplitUniversalOrderID("313943552673")
}
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
index := strings.Index(universalOrderID, "|")
if index != -1 {
orderID = universalOrderID[:index]
vendorID = int(utils.Str2Int64(universalOrderID[index+1:]))
} else {
if vendorID = GetPossibleVendorIDFromVendorOrderID(universalOrderID); vendorID == -1 {
panic(fmt.Sprintf("unkown order type, orderID:%s", universalOrderID))
}
orderID = universalOrderID
}
return orderID, vendorID
}
func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
vendorID = -1
//if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
orderIDLen := len(vendorOrderID)
// 5287873015048 13 wsc
// 15380342248732 14 old ebai order
// 800402581000221 15,16 jd order
// 33437032333978492 17 mtwm order
// 3022716176275221584 19 elm order, new ebai order
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位订单号的前两位取的是当年的最后两位数2020取的20以适应业务的发展。
// 改造点:
// 1、订单号位数变化由原有15位数增加1位数调整为16位数对接商家需检查是否有对订单号位数做长度校验。
// 2、第一位数字发生变化由原来9开头调整为当年年份后两位数如2020年订单开头为20
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
vendorID = 0
} else if orderIDLen == len("3022716176275221584") {
// vendorID = model.VendorIDELM
vendorID = 3 // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位和饿了么订单ID“eleme_order_id”字段格式保持一致。
} else if orderIDLen == len("15380342248732") {
if vendorOrderID[:2] == "88" {
vendorID = 9
} else {
vendorID = 3
}
} else if orderIDLen == len("33437032333978492") || orderIDLen == len("116379390766579767") {
vendorID = 1
} else if orderIDLen == len("5287873015048") {
vendorID = 11
} else if orderIDLen == len("1000004390") {
vendorID = 9
} else if orderIDLen == len("18100216009800000001") || orderIDLen == len("191075245758000000039") {
vendorID = 5
}
return vendorID
}

View File

@@ -328,7 +328,7 @@ func TestDeleteStoreSku(t *testing.T) {
}
func TestDeleteSku(t *testing.T) {
shopId := "100829"
shopId := "804627"
param1 := &SkuListParams{
Page: 1,
PageSize: 100,

View File

@@ -29,8 +29,8 @@ func init() {
func TestQueryOneStore(t *testing.T) {
api = New("6705486294797503379", "c1e6c280-e618-4103-9d0a-673bc54fb22e", "51658", "")
//token, err := api.GetAccessToken()
api.accessToken = "8cffab79-4dab-4a9a-a609-c1ff6b14109b"
data, err := api.GetStore("20002")
api.accessToken = "eb855784-ca08-460b-be73-5681ceb28222"
data, err := api.GetStore("5000009")
fmt.Println(data)
fmt.Println(err)
}

View File

@@ -23,10 +23,10 @@ func init() {
//api = New("589", "a81eb3df418d83d6a1a4b7c572156d2f", "", "")
// 果园
api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "")
//api = New("4123", "df2c88338b85f830cebce2a9eab56628", "", "")
//商超
//api = New("5873", "41c479790a76f86326f89e8048964739", "", "token_hGnQOvCSkfrCOXFLHA1NMQ")
api = New("5873", "41c479790a76f86326f89e8048964739", "", "token_n49KrTnbe-Qatd-80sFOnQ")
//cookieStr := `
// acctId=57396785; token=0bWbK5VbK50E2BmIhIH2zHB-am_y7mB37yXHm6RLZWx4*; wmPoiId=-1;
//`
@@ -53,7 +53,7 @@ func TestGetOAuthCode(t *testing.T) {
}
func TestPreparationMealComplete(t *testing.T) {
api.PreparationMealComplete(900658760944919842)
api.PreparationMealComplete(3901564910320888932)
}
func TestGetAccessToken(t *testing.T) {

View File

@@ -31,7 +31,7 @@ func getTimeFromTimestamp(timeStamp int64) time.Time {
}
func TestOrderGetOrderDetail(t *testing.T) {
result, err := api.OrderGetOrderDetail(2001521861299113073, false)
result, err := api.OrderGetOrderDetail(5401564660946475322, false)
if err != nil {
t.Fatal(err)
}

View File

@@ -6,6 +6,7 @@ import (
"git.rosy.net.cn/baseapi/utils"
"strings"
"testing"
"time"
)
const (
@@ -24,16 +25,30 @@ func TestPoiGetIDs(t *testing.T) {
}
func Test1111(t *testing.T) {
result, err := api.PoiMGet([]string{"17821732"})
if err != nil {
fmt.Println(err)
storeIds := []int64{
12524795,
}
for _, v := range result {
if strings.Contains(v.Name, "京西") {
data := fmt.Sprintf("%s %s ", v.AppPoiCode, v.Name) + fmt.Sprintf("<table><img src=%s height=100 width=100></table>", v.PicURL)
fmt.Println(data)
for k, v := range storeIds {
result, err := api.PoiMGet([]string{utils.Int64ToStr(v)})
if err != nil {
fmt.Println(k)
continue
}
if result == nil || len(result) == 0 {
fmt.Println(k)
continue
}
for _, v2 := range result {
if strings.Contains(v2.Name, "京西") {
fmt.Println(fmt.Sprintf("<table><img src=%s height=100 width=100></table>", v2.PicURL))
} else {
fmt.Println(k)
}
}
time.Sleep(200 * time.Microsecond)
}
}
func TestPoiMGet(t *testing.T) {
result, err := api.PoiMGet([]string{"17821732"})

View File

@@ -22,8 +22,8 @@ func TestName(t *testing.T) {
}
func TestGetOrderDetail(t *testing.T) {
requestParam := &request591.AlibabaAelophyOrderGetRequest{OrderGetRequest: &domain591.AlibabaAelophyOrderGetOrderGetRequest{
StoreId: utils.String2Pointer("JX667128"),
BizOrderId: utils.Int64ToPointer(8000211756001500978),
StoreId: utils.String2Pointer("JX100236"),
BizOrderId: utils.Int64ToPointer(8000245939558000686),
}}
data, err := apiTao.QueryOrderDetail(requestParam)
@@ -74,13 +74,13 @@ func Test222(t *testing.T) {
// 接单
func TestDeliveryFinishACCEPTED(t *testing.T) {
orderID := 8000101702997900468
storeID := "JX102364"
orderID := 8000253695335600623
storeID := "JX666900"
param := &request591.AlibabaAelophyOrderWorkCallbackRequest{}
param.WorkCallbackRequest = &domain591.AlibabaAelophyOrderWorkCallbackWorkCallbackRequest{
StoreId: utils.String2Pointer("JX102364"),
StoreId: utils.String2Pointer(storeID),
BizOrderId: utils.Int64ToPointer(int64(orderID)),
Status: utils.String2Pointer(OrderStatusSuccess),
Status: utils.String2Pointer(OrderStatusPickedUp),
StatusRemark: nil,
//DelivererName: utils.String2Pointer("张廷"),
//DelivererPhone: utils.String2Pointer("SIGN"),
@@ -107,7 +107,7 @@ func TestDeliveryFinishACCEPTED(t *testing.T) {
workCallbackSubOrderInfoList = append(workCallbackSubOrderInfoList, workCallbackSubOrderInfo)
}
param.WorkCallbackRequest.WorkCallbackSubOrderInfoList = &workCallbackSubOrderInfoList
apiTao.SetToken("50000C00432zMSClqLiSDjBr2NyiazjtFmsgTOdbBfti16a73f18k0XDfkUQywSmcjfC")
apiTao.SetToken("50000C00e13l3SYxqadamvelw15656b52A0xeXfaS8nyVCgitlzIq1nDwFzYdcQpIsVz")
//apiTao.SetToken("50002C01524csKWniqfypk8dbshKRTeFIOIy1a46c0cfgsvodWjsseMsXqpvWvECMj1")
err = apiTao.DeliveryFinish(param)
fmt.Println(err)

View File

@@ -14,7 +14,12 @@ const (
MsgTypePayZFB = "VSP511" //支付宝
MsgTypeRefundZFB = "VSP513"
TrxStatusSuccess = "0000"
TrxStatusSuccess = "0000" // 交易成功
TrxStatusTransaction = "2000" // 支付中
TrxStatusTransaction2 = "2008" // 支付中
OnlinePayStatusSuccess = "SUCCESS"
OnlinePayStatusFail = "FAIL"
MisStatusSuccess = "Y0000" // 调用成功
)
type CallBackResult struct {
@@ -57,3 +62,50 @@ func (a *API) GetCallbackMsg(request *http.Request) (call *CallBackResult, err e
utils.Map2StructByJson(mapData, &call, false)
return call, err
}
// CallBackResultOnlinePay 扫码支付回调
type CallBackResultOnlinePay struct {
AppID string `json:"appID"`
OuttrxID string `json:"outtrxID"`
TrxCode string `json:"trxCode"`
TrxID string `json:"trxID"`
TrxAmt string `json:"trxAmt"`
TrxDate string `json:"trxDate"`
PayTime string `json:"payTime"`
ChnlTrxID string `json:"chnlTrxID"`
TrxStatus string `json:"trxStatus"`
CusID string `json:"cusID"`
TermNo string `json:"termNo"`
TermBatchid string `json:"termBatchid"`
TermTraceno string `json:"termTraceno"`
TermAuthno string `json:"termAuthno"`
TermRefnum string `json:"termRefnum"`
TrxReserved string `json:"trxReserved"`
SrcTrxid string `json:"srcTrxid"`
CusorderID string `json:"cusorderID"`
Acct string `json:"acct"`
Fee string `json:"fee"`
SignType string `json:"signType"`
Cmid string `json:"cmid"`
Chnlid string `json:"chnlid"`
Sign string `json:"sign"`
Initamt string `json:"initamt"`
Chnldata string `json:"chnldata"`
Accttype string `json:"accttype"`
Bankcode string `json:"bankcode"`
Logonid string `json:"logonid"`
}
func (a *API) GetCallbackOnlinePayMsg(request *http.Request) (call *CallBackResultOnlinePay, err error) {
data, err := ioutil.ReadAll(request.Body)
if err != nil {
return nil, err
}
values, err := utils.HTTPBody2Values(data, false)
if err != nil {
return nil, err
}
mapData := utils.URLValues2Map(values)
utils.Map2StructByJson(mapData, &call, false)
return call, err
}

View File

@@ -0,0 +1,282 @@
package tonglianpayapi
import (
"crypto/md5"
"fmt"
"git.rosy.net.cn/baseapi/platformapi"
"net/http"
"sort"
"strings"
)
const (
prodURL = "https://vsp.allinpay.com/apiweb"
prodURL2 = "https://syb.allinpay.com/apiweb"
sepcAction = "unitorder/pay"
sepcAction2 = "h5unionpay/unionorder"
sigKey = "sign"
PayTypeWxXcx = "W06"
PayTypeWxCode = "W01"
PayTypeZfbApp = "A03"
PayTypeZfbQrcode = "A01"
PayTypeZfbJS = "A02"
PayTypeH5 = "H5"
ResponseCodeSuccess = "SUCCESS"
ResponseCodeFail = "FAIL"
)
type API struct {
appID string
cusID string
appKey string
client *http.Client
config *platformapi.APIConfig
}
func New(appID, appKey, cusID string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
appID: appID,
appKey: appKey,
cusID: cusID,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) signParam(params map[string]interface{}) (sig string) {
var valueList []string
for k, v := range params {
if k != sigKey {
if str := fmt.Sprint(v); str != "" {
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
}
}
}
valueList = append(valueList, fmt.Sprintf("key=%s", a.appKey))
sort.Sort(sort.StringSlice(valueList))
sig = strings.Join(valueList, "&")
binSig := md5.Sum([]byte(sig))
sig = fmt.Sprintf("%X", binSig)
return sig
}
type CreateUnitorderOrderParam struct {
CusID string `json:"cusid"`
AppID string `json:"appid"`
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
NotifyUrl string `json:"notifyUrl"` //接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。
Acct string `json:"acct"`
PayType string `json:"paytype"`
SubAppID string `json:"subAppID"`
}
type CreateUnitOrderOrderResult struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
CusID string `json:"cusID"`
AppID string `json:"appID"`
TrxID string `json:"trxID"`
ChnltrxID string `json:"chnltrxID"`
Reqsn string `json:"reqsn"`
RandomStr string `json:"randomStr"`
TrxStatus string `json:"trxStatus"`
FinTime string `json:"finTime"`
ErrMsg string `json:"errMsg"`
PayInfo string `json:"payInfo"`
Sign string `json:"sign"`
}
type PayInfo struct {
AppID string `json:"appID"`
TimeStamp string `json:"timeStamp"`
NonceStr string `json:"nonceStr"`
Package string `json:"package"`
SignType string `json:"signType"`
PaySign string `json:"paySign"`
}
type PayRefundParam struct {
CusID string `json:"cusid"`
AppID string `json:"appid"`
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
OldReqsn string `json:"oldReqsn"`
Remark string `json:"remark"`
RandomStr string `json:"randomStr"`
Sign string `json:"sign"`
TrxID string `json:"trxID"`
OldTrxID string `json:"oldTrxID"`
}
type PayRefundResult struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
CusID string `json:"cusID"`
AppID string `json:"appID"`
TrxID string `json:"trxID"`
Reqsn string `json:"reqsn"`
TrxStatus string `json:"trxStatus"`
FinTime string `json:"finTime"`
ErrMsg string `json:"errMsg"`
RandomStr string `json:"randomStr"`
Sign string `json:"sign"`
Fee string `json:"fee"`
TrxCode string `json:"trxCode"`
}
type CreateH5UnitorderOrderParam struct {
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
NotifyUrl string `json:"notifyUrl"` //接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。
Charset string `json:"charset"`
Returl string `json:"returl"`
Body string `json:"body"`
}
// OnlinePayParam 扫码枪扫码支付参数
type OnlinePayParam struct {
//参数 参数名称 可空 备注
Orgid string `json:"orgid"` // 集团/代理商商户号 是 共享集团号/代理商参数时必填
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Version string `json:"version"` // 版本号接口版本号 可
Randomstr string `json:"randomstr"` // 随机字符串 否 商户自行生成的随机字符串
Trxamt string `json:"trxamt"` // 交易金额单位为分 否
Reqsn string `json:"reqsn"` // 商户交易单号 否 保证商户平台唯一
Body string `json:"body"` // 订单商品名称,为空则以商户名作为商品名称 是
Remark string `json:"remark"` // 备注 是 禁止出现+,空格,/?%#& = 这几类特殊符号
Authcode string `json:"authcode"` // 支付授权码如微信, 支付宝, 银联的付款二维码 否
LimitPay string `json:"limit_pay"` // 支付限制 no_credit--指定不能使用信用卡支付 是 32 暂时只对微信支付和支付宝, 支付宝支付有效, 仅支持no_credit
GoodsTag string `json:"goods_tag"` // 订单优惠标记 订单优惠标记,用于区分订单是否可以享受优惠,字段内容在微信后台配置券时进行设置,说明详见代金券或立减优惠 是 只对微信支付有效
Benefitdetail string `json:"benefitdetail"` // 优惠信息Benefitdetail的json字符串, 注意是String 填写格式详见附录5.8 是
SubAppid string `json:"sub_appid"` // 微信子appid 微信小程序/微信公众号/APP的appid 是 只对微信支付有效
Chnlstoreid string `json:"chnlstoreid"` // 渠道门店编号 商户在支付渠道端的门店编号 对于支付宝支付,支付宝门店编号 对于微信支付,微信门店编号
Subbranch string `json:"subbranch"` // 门店号 是 4
Idno string `json:"idno"` // 证件号实名交易必填.填了此字段就会验证证件号和姓名 是 暂只支持支付宝
Extendparams string `json:"extendparams"` // 拓展参数 json字符串注意是String一般用于渠道的活动参数填写 是 参考5.9拓展参数附录说明
Truename string `json:"truename"` // 付款人真实姓名实名交易必填.填了此字段就会验证证件号和姓名 是 暂只支持支付宝
Asinfo string `json:"asinfo"` // 分账信息 格式:cusid:type:amount cusid:type:amount… 其中 cusid:接收分账的通联商户号 type分账类型01按金额 02按比率 如果分账类型为02则分账比率为0.5表示50%。如果分账类型为01则分账金额以元为单位表示 是
Fqnum string `json:"fqnum"` // 分期
NotifyUrl string `json:"notify_url"` // 交易结果通知地址 接收交易结果的通知回调地址通知url必须为直接可访问的url不能携带参数。 https只支持默认端口 是
Signtype string `json:"signtype"` /// 签名方式 是
Unpid string `json:"unpid"` // 银联pid 仅支持代理商/服务商角色调用
Sign string `json:"sign"` // 签名 详见安全规范 否
Terminfo string `json:"terminfo"` // 终端信息终端信息的json字符串 详见附录5.10终端字段说明 否
Operatorid string `json:"operatorid"` // 收银员号 是
}
type TerminfoBase struct {
Termno string `json:"termno"` // 终端号 必填
Devicetype string `json:"devicetype"` // 设备类型 必填
Termsn string `json:"termsn"` // 终端序列号
Encryptrandnum string `json:"encryptrandnum"` // 加密随机因子
Secrettext string `json:"secrettext"` // 密文数据
Appversion string `json:"appversion"` // 终端程序版本号
Longitude string `json:"longitude"` // 经度 银联扫码必送
Latitude string `json:"latitude"` // 纬度 银联扫码必送
Deviceip string `json:"deviceip"` // 终端Ip 如微信支付宝交易经纬度未上送,该字段必送
}
// OnlinePayResult 扫码枪支付返回参数
type OnlinePayResult struct {
Retcode string `json:"retcode"` // SUCCESS/FAIL
Retmsg string `json:"retmsg"` // 返回码说明
}
type OnlinePayRetMsg struct {
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Trxid string `json:"trxid"` // 收银宝平台的交易流水号
Chnltrxid string `json:"chnltrxid"` // 例如微信,支付宝平台的交易单号
Reqsn string `json:"reqsn"` // 商户的交易订单号
Trxstatus string `json:"trxstatus"` // 交易的状态,
Acct string `json:"acct"` // 微信支付-用户的微信openid支付宝支付-用户user_id
Trxcode string `json:"trxcode"` // 交易类型
Fintime string `json:"fintime"` // yyyyMMddHHmmss
Errmsg string `json:"errmsg"` // 失败的原因说明
Randomstr string `json:"randomstr"` // 随机生成的字符串
Initamt string `json:"initamt"` // 原交易金额
Trxamt string `json:"trxamt"` // 实际交易金额
Fee string `json:"fee"` // 手续费
Cmid string `json:"cmid"` // 渠道子商户号
Chnlid string `json:"chnlid"` // 渠道号
Chnldata string `json:"chnldata"` // 渠道信息
Accttype string `json:"accttype"` // 借贷标识
Sign string `json:"sign"` // 签名
}
// PayTransactionStatusQuery 交易状态查询
type PayTransactionStatusQuery struct {
Orgid string `json:"orgid"` // 集团/代理商商户号 是 共享集团号/代理商参数时必填
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Version string `json:"version"` // 版本号接口版本号 可
Reqsn string `json:"reqsn"` // 商户交易单号 否 保证商户平台唯一
Trxid string `json:"trxid"` // 收银宝平台的交易流水号
Randomstr string `json:"randomstr"` // 随机字符串 否 商户自行生成的随机字符串
Signtype string `json:"signtype"` /// 签名方式 是
Sign string `json:"sign"` // 签名 详见安全规范 否
}
type PayTransactionStatusResult struct {
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Trxid string `json:"trxid"` // 收银宝平台的交易流水号
Chnltrxid string `json:"chnltrxid"` // 例如微信,支付宝平台的交易单号
Reqsn string `json:"reqsn"` // 商户的交易订单号
Trxcode string `json:"trxcode"` // 交易类型
Trxamt string `json:"trxamt"` // 实际交易金额
Trxstatus string `json:"trxstatus"` // 交易的状态,
Acct string `json:"acct"` // 支付平台用户标识
Fintime string `json:"fintime"` // yyyyMMddHHmmss
Randomstr string `json:"randomstr"` // 随机生成的字符串
Errmsg string `json:"errmsg"` // 失败的原因说明
Cmid string `json:"cmid"` // 渠道子商户号
Chnlid string `json:"chnlid"` // 渠道号
Initamt string `json:"initamt"` // 原交易金额
Fee string `json:"fee"` // 手续费
Chnldata string `json:"chnldata"` // 渠道信息
Accttype string `json:"accttype"` // 借贷标识
Bankcode string `json:"bankcode"` // 所属银行
Logonid string `json:"logonid"` // 买家账号
Sign string `json:"sign"` // 签名
}
// OnLineOrderRefundParam 订单退款参数
type OnLineOrderRefundParam struct {
Orgid string `json:"orgid"` // 集团/代理商商户号 是 共享集团号/代理商参数时必填
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Version string `json:"version"` // 版本号接口版本号 可
Trxamt string `json:"trxamt"` // 交易金额单位为分 否
Reqsn string `json:"reqsn"` // 商户交易单号 否 保证商户平台唯一
Oldreqsn string `json:"oldreqsn"` // 原交易订单号 是
Oldtrxid string `json:"oldtrxid"` // 原交易流水 是
Remark string `json:"remark"` // 备注 是 禁止出现+,空格,/?%#& = 这几类特殊符号
Benefitdetail string `json:"benefitdetail"` // 优惠信息
Randomstr string `json:"randomstr"` // 随机字符串 否 商户自行生成的随机字符串
Signtype string `json:"signtype"` /// 签名方式 是
Sign string `json:"sign"` // 签名 详见安全规范 否
}
type OnLineOrderRefundResult struct {
Cusid string `json:"cusid"` // 商户号实际交易的商户号 否
Appid string `json:"appid"` // 应用ID平台分配的APPID 否
Trxid string `json:"trxid"` // 收银宝平台的交易流水号
Reqsn string `json:"reqsn"` // 商户的交易订单号
Trxstatus string `json:"trxstatus"` // 交易的状态,
Fintime string `json:"fintime"` // yyyyMMddHHmmss
Errmsg string `json:"errmsg"` // 失败的原因说明
Fee string `json:"fee"` // 手续费
Trxcode string `json:"trxcode"` // 交易类型
Randomstr string `json:"randomstr"` // 随机生成的字符串
Chnltrxid string `json:"chnltrxid"` // 例如微信,支付宝平台的交易单号
Chnldata string `json:"chnldata"` // 渠道信息
Bankcode string `json:"bankcode"` // 所属银行
Sign string `json:"sign"` // 签名
}

View File

@@ -0,0 +1,194 @@
package tonglianpayapi
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"fmt"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"net/http"
"sort"
"strings"
)
const (
//RSA私钥(非JAVA适用)
RSAPrivateKeyNotJava = `MIIEpAIBAAKCAQEAx9qhvqwyZ5hUKoxErxjgOgpjipbmJr20tGCtd/7UXCksVE9S/JWF6+LuT9jKAQpDDU4Dniu5mpwp6vfz2S7D51bO+S2mmSyiV6//NHpWZJwP9Lsb2fbU0tJUNiXGx3P79sA7ZDi5hkho59CX+tOr/gVDKXTb4Rbyj50+N+Rxt3i/Kd4Sf8AMRodP4SxcOjS4pbmwLFcD5H35czvXSRBQkHAptJ6keiYJLmi2ylsLWnBgf0BZYp04i5EVxiUT389ji7WNOUpNedb3wjOio877VatNm4XIZx0BFZVF8ZFEzEJkVXRAxRlR71nl1uKpNPVqfPQZ8pY3RrUmCxOwnJl5vQIDAQABAoIBAB3U4jjabkmtYL7bIjN6xJmVTGd2/9K/lXYpSitzs9Iv6SiKkKoYTZ24yXbMttZx6DFXuE2HXFSaQ92JdnIwO1jQSePC7y/FDFSHdlIogrXQ38bZmR4vbHQtphlRCTtjcjRSXGso1nSXYWVc6xqrNuybb3uEMIAIU1uhjpR8Ooc2sMfmpNdqCS5SKngIsRj5FQZzBPUoBiAlKiYck/UJzUgdVyxz5hpaFqB2V6VciD3E/PSa6OtSTPVO7a1KUD1rmvADZTmAYSqYwRBqZxkb42MNDtOW8YqRFC/rTlSQOo76XvT0AGSY2ZvFC89LrIZc9hF76k8OfCi8XjrwrMKgbpcCgYEA6/WiwthWy41Ch9R9xCubkPYfulNjq9CKbYyWnmmARnnhM5iRYJidqyfw1IbSVVm9Qy3o3VBnYocOTRJUTmOmpQgWqI4t/HjCZiFZeKF30F9ytl1urCbkXYWA2lygf2ZUYiCt3/CNC0bct4nZa42sGu3TXYZKcpVqlZT6tWywu8sCgYEA2NP4Zz5zJGzskhVdsEJbL7ttv/yX7X/g6AW3IhcI108bWfoA+i6YjbDsC8aftgIHPheaW/6n+oirDwoYdgrWa2/eCIKBo5uchtDmUb8qIXog1RbryKqOevLDkGRlJ8NAOIZfGwjT3pfhbtM+wvH5PCFBywoMlxz2sWZ2x4Vzf5cCgYEAza8Jeh9rSXSRkiXAm8gHi42AisM2FwdqI6RxhxUgJE8J6BgOYc2nYxMl85yyrIPVX0Idww3bkR95b+WSZ+Kl2SX72mJV48bAbpaTj3vxHUqWjDFVz+r3Fi7R64biwStKU195McRWroXO0I7xX7fXVoIJxXTSYJ+ukUWUZaGhTZECgYEAuHv6IVYYP8jRrCWztjFvRniRk8VGOxQP9zpNrBqvMgqjufWl+TfGIuCCpi5UW1b0dJc+hcFxiQ/Zg41SbLUh5P2ki9cGmH7hOi/pl2owXZV88/FxoiXD3sZJMMTK8H8HWFC0ANuM8RqG+3WPM+0P42JkiW2+cqB5IU2OCIr6T3cCgYBSLkui8zbMJB0TfE+KGxdm3e+sX26ZE2ZqQmTfJoRcxGgkWC7oY8HdIwws1uFeO38C5SMkkT8YlJghAjIIsfIUuCWQc5tBwvcb5f78/iJRUVgHXl3dH+9HvJKh/I4NeTIX6NTlaOrkUjgnkLLWbU7+b+3SCsVnvKH7uEm5cH0Ejg==`
//RSA公钥
RSAPublicKey = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9qhvqwyZ5hUKoxErxjgOgpjipbmJr20tGCtd/7UXCksVE9S/JWF6+LuT9jKAQpDDU4Dniu5mpwp6vfz2S7D51bO+S2mmSyiV6//NHpWZJwP9Lsb2fbU0tJUNiXGx3P79sA7ZDi5hkho59CX+tOr/gVDKXTb4Rbyj50+N+Rxt3i/Kd4Sf8AMRodP4SxcOjS4pbmwLFcD5H35czvXSRBQkHAptJ6keiYJLmi2ylsLWnBgf0BZYp04i5EVxiUT389ji7WNOUpNedb3wjOio877VatNm4XIZx0BFZVF8ZFEzEJkVXRAxRlR71nl1uKpNPVqfPQZ8pY3RrUmCxOwnJl5vQIDAQAB`
//RSA私钥(JAVA适用)
RSAPrivateKeyJava = `MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH2qG+rDJnmFQqjESvGOA6CmOKluYmvbS0YK13/tRcKSxUT1L8lYXr4u5P2MoBCkMNTgOeK7manCnq9/PZLsPnVs75LaaZLKJXr/80elZknA/0uxvZ9tTS0lQ2JcbHc/v2wDtkOLmGSGjn0Jf606v+BUMpdNvhFvKPnT435HG3eL8p3hJ/wAxGh0/hLFw6NLilubAsVwPkfflzO9dJEFCQcCm0nqR6JgkuaLbKWwtacGB/QFlinTiLkRXGJRPfz2OLtY05Sk151vfCM6KjzvtVq02bhchnHQEVlUXxkUTMQmRVdEDFGVHvWeXW4qk09Wp89BnyljdGtSYLE7CcmXm9AgMBAAECggEAHdTiONpuSa1gvtsiM3rEmZVMZ3b/0r+VdilKK3Oz0i/pKIqQqhhNnbjJdsy21nHoMVe4TYdcVJpD3Yl2cjA7WNBJ48LvL8UMVId2UiiCtdDfxtmZHi9sdC2mGVEJO2NyNFJcayjWdJdhZVzrGqs27Jtve4QwgAhTW6GOlHw6hzawx+ak12oJLlIqeAixGPkVBnME9SgGICUqJhyT9QnNSB1XLHPmGloWoHZXpVyIPcT89Jro61JM9U7trUpQPWua8ANlOYBhKpjBEGpnGRvjYw0O05bxipEUL+tOVJA6jvpe9PQAZJjZm8ULz0ushlz2EXvqTw58KLxeOvCswqBulwKBgQDr9aLC2FbLjUKH1H3EK5uQ9h+6U2Or0IptjJaeaYBGeeEzmJFgmJ2rJ/DUhtJVWb1DLejdUGdihw5NElROY6alCBaoji38eMJmIVl4oXfQX3K2XW6sJuRdhYDaXKB/ZlRiIK3f8I0LRty3idlrjawa7dNdhkpylWqVlPq1bLC7ywKBgQDY0/hnPnMkbOySFV2wQlsvu22 //Jftf+DoBbciFwjXTxtZ+gD6LpiNsOwLxp+2Agc+F5pb/qf6iKsPChh2CtZrb94IgoGjm5yG0OZRvyoheiDVFuvIqo568sOQZGUnw0A4hl8bCNPel+Fu0z7C8fk8IUHLCgyXHPaxZnbHhXN/lwKBgQDNrwl6H2tJdJGSJcCbyAeLjYCKwzYXB2ojpHGHFSAkTwnoGA5hzadjEyXznLKsg9VfQh3DDduRH3lv5ZJn4qXZJfvaYlXjxsBulpOPe/EdSpaMMVXP6vcWLtHrhuLBK0pTX3kxxFauhc7QjvFft9dWggnFdNJgn66RRZRloaFNkQKBgQC4e/ohVhg/yNGsJbO2MW9GeJGTxUY7FA/3Ok2sGq8yCqO59aX5N8Yi4IKmLlRbVvR0lz6FwXGJD9mDjVJstSHk/aSL1waYfuE6L+mXajBdlXzz8XGiJcPexkkwxMrwfwdYULQA24zxGob7dY8z7Q/jYmSJbb5yoHkhTY4IivpPdwKBgFIuS6LzNswkHRN8T4obF2bd76xfbpkTZmpCZN8mhFzEaCRYLuhjwd0jDCzW4V47fwLlIySRPxiUmCECMgix8hS4JZBzm0HC9xvl/vz+IlFRWAdeXd0f70e8kqH8jg15Mhfo1OVo6uRSOCeQstZtTv5v7dIKxWe8ofu4SblwfQSO`
//SM2公钥
SM2PublicKey = `MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE7yCR6yp3jPOgBTqWqE9D3ugudcsi4epjq3EJ6mq3Y0nrR489Pld7V5yk+QuH2SUZMFmu46/adlnN/+cd496lkg==`
//SM2私钥
SM2PrivateKey = `MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg1Rj + skv1B3dGwe2wGy9OF6N4vqxAGM44MR6e2kWTxhegCgYIKoEcz1UBgi2hRANCAATvIJHrKneM86AFOpaoT0Pe6C51yyLh6mOrcQnqardjSetHjz0 + V3tXnKT5C4fZJRkwWa7jr9p2Wc3/5x3j3qWS`
// 测试私钥
cusRsaPrivateTestKey = `MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJgHMGYsspghvP+yCbjLG43CkZuQ3YJyDcmEKxvmgblITfmiTPx2b9Y2iwDT9gnLGExTDm1BL2A8VzMobjaHfiCmTbDctu680MLmpDDkVXmJOqdlXh0tcLjhN4+iDA2KkRqiHxsDpiaKT6MMBuecXQbJtPlVc1XjVhoUlzUgPCrvAgMBAAECgYAV9saYTGbfsdLOF5kYo0dve1JxaO7dFMCcgkV+z2ujKtNmeHtU54DlhZXJiytQY5Dhc10cjb6xfFDrftuFcfKCaLiy6h5ETR8jyv5He6KH/+X6qkcGTkJBYG1XvyyFO3PxoszQAs0mrLCqq0UItlCDn0G72MR9/NuvdYabGHSzEQJBAMXB1/DUvBTHHH4LiKDiaREruBb3QtP72JQS1ATVXA2v6xJzGPMWMBGQDvRfPvuCPVmbHENX+lRxMLp39OvIn6kCQQDEzYpPcuHW/7h3TYHYc+T0O6z1VKQT2Mxv92Lj35g1XqV4Oi9xrTj2DtMeV1lMx6n/3icobkCQtuvTI+AcqfTXAkB6bCz9NwUUK8sUsJktV9xJN/JnrTxetOr3h8xfDaJGCuCQdFY+rj6lsLPBTnFUC+Vk4mQVwJIE0mmjFf22NWW5AkAmsVaRGkAmui41Xoq52MdZ8WWm8lY0BLrlBJlvveU6EPqtcZskWW9KiU2euIO5IcRdpvrB6zNMgHpLD9GfMRcPAkBUWOV/dH13v8V2Y/Fzuag/y5k3/oXi/WQnIxdYbltad2xjmofJ7DbB7MJqiZZD8jlr8PCZPwRNzc5ntDStc959`
// 回调地址
OnlinePayCallbackUrl = "https://callback.jxc4.com/tongLian/onLinePay"
// 接口地址
OnlinePayUrl = `https://vsp.allinpay.com/apiweb/unitorder/scanqrpay` // 扫码支付
OnLineTransactionQuery = `https://vsp.allinpay.com/apiweb/tranx/query` // 交易查询,查询订单的支付状态
OnLineRefund = `https://vsp.allinpay.com/apiweb/tranx/refund` // 同一退款接口
)
const (
EncryptionRsa = "RSA" // 加密方式
)
var (
TransactionStatus = map[string]string{
"0000": "交易成功",
"1001": "交易不存在",
"2008": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
"2000": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
"3888": "流水号重复",
"3099": "渠道商户错误",
"3014": "交易金额小于应收手续费",
"3031": "校验实名信息失败",
"3088": "交易未支付",
"3089": "撤销异常,如已影响资金24小时内会做差错退款处理",
"3050": "交易已被撤销",
"3999": "1",
"3889": "1",
"3045": "1",
}
)
// CreateOnlineBankOrder 网银创建订单(扫码枪,扫二维码支付)
func (a *API) CreateOnlineBankOrder(param *OnlinePayParam) (statusCode, trxid, errRemake string, err error) {
onlineReq := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(OnlinePayUrl, onlineReq)
if err != nil {
return "", "", "", err
}
// 请求接口成功后通联系统返回JSON字符串数据把除sign之外的其他所有非空字段组成键值对进行同样的排序和组装处理并用通联的公钥进行验签
// 暂时不考虑验签
if result["retcode"].(string) != "SUCCESS" {
return "", "", "", fmt.Errorf(result["retmsg"].(string))
}
payInfo := &OnlinePayRetMsg{}
if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
return "", "", "", err
}
return payInfo.Trxstatus, payInfo.Trxid, payInfo.Errmsg, nil
}
// QueryPayTransaction 订单交易状态查询
func (a *API) QueryPayTransaction(param *PayTransactionStatusQuery) (statusCode, errRemake string, err error) {
onlineReq := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(OnLineTransactionQuery, onlineReq)
if err != nil {
return "", "", err
}
if result["retcode"].(string) != "SUCCESS" {
return "", "", fmt.Errorf(result["retmsg"].(string))
}
payInfo := &PayTransactionStatusResult{}
if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
return "", "", err
}
return payInfo.Trxstatus, payInfo.Errmsg, nil
}
// OrderRefund 退单
func (a *API) OrderRefund(param *OnLineOrderRefundParam) (statusCode, errRemake string, err error) {
onlineReq := utils.Struct2Map(param, "", false)
result, err := a.AccessAPI2(OnLineRefund, onlineReq)
if err != nil {
return "", "", err
}
if result["retcode"].(string) != "SUCCESS" {
return "", "", fmt.Errorf(result["retmsg"].(string))
}
payInfo := &OnLineOrderRefundResult{}
if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
return "", "", err
}
return payInfo.Trxstatus, payInfo.Errmsg, nil
}
func (a *API) AccessAPI2(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
params := make(map[string]interface{})
params["appid"] = a.appID
params["cusid"] = a.cusID
params["randomstr"] = utils.GetUUID()
params["version"] = "12"
params = utils.MergeMaps(params, bizParams)
sign, err := a.signParamRSA(params, RSAPrivateKeyNotJava)
if err != nil {
return nil, err
}
params["sign"] = sign
err = platformapi.AccessPlatformAPIWithRetry(a.client,
func() *http.Request {
request, _ := http.NewRequest(http.MethodPost, action, strings.NewReader(utils.Map2URLValues(params).Encode()))
request.Header.Set("charset", "UTF-8")
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
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["retcode"])
if returnCode != OnlinePayStatusSuccess {
errLevel = platformapi.ErrLevelGeneralFail
err = utils.NewErrorCode(utils.Interface2String(jsonResult1["retcode"])+utils.Interface2String(jsonResult1["retmsg"]), returnCode)
}
retVal = jsonResult1
}
return errLevel, err
})
return retVal, err
}
func (a *API) signParamRSA(params map[string]interface{}, RSAPrivate string) (sig string, err error) {
decodeString, err := base64.StdEncoding.DecodeString(RSAPrivate)
if err != nil {
return "", err
}
private, err := x509.ParsePKCS1PrivateKey(decodeString) //之前看java demo中使用的是pkcs8
if err != nil {
return "", err
}
var valueList []string
for k, v := range params {
if k != sigKey {
if str := fmt.Sprint(v); str != "" {
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
}
}
}
sort.Sort(sort.StringSlice(valueList))
context := strings.Join(valueList, "&")
h := crypto.Hash.New(crypto.SHA1) //进行SHA1的散列
h.Write([]byte(context))
hashed := h.Sum(nil)
// 进行rsa加密签名
signedData, err := rsa.SignPKCS1v15(rand.Reader, private, crypto.SHA1, hashed)
if err != nil {
return "", err
}
signData := base64.StdEncoding.EncodeToString(signedData)
return signData, nil
}

View File

@@ -0,0 +1,101 @@
package tonglianpayapi
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"testing"
)
func TestSignRSA(t *testing.T) {
sginParma := map[string]interface{}{
"appid": "00000051",
"cusid": "990581007426001",
"randomstr": "82712208",
"signtype": "RSA",
"trxid": "112094120001088317",
"version": "11",
}
sgin, _ := api.signParamRSA(sginParma, cusRsaPrivateTestKey)
fmt.Println(sgin)
data2 := `ce6EAOj4rhoBMJM5MJCNG4qQ/CVMTWkoRuSGpSzRAnD3U3V5QyHkQUEej2eZXRaa+qSbw2/IJJSPV0sPuAia1+ccb7OnvxyZqkV9wQyimX6qAMz0K+UWFhQ5McCcQ/XsFhhezoVd5QgL7PtdvuK1AtjuzA3J9yzNmwuPssPnKnc=`
fmt.Println(sgin == data2)
}
func TestOnlinePayData(t *testing.T) {
param := &OnlinePayParam{
Orgid: "",
Cusid: "", // 不用
Appid: "", // 不用
Version: "", // 不用
Randomstr: "", // 不用
Trxamt: "1",
Reqsn: "202504221811",
Body: "测试订单",
Remark: "这是一个测试",
Authcode: "133040799834193135", // 支付授权码
LimitPay: "",
GoodsTag: "",
Benefitdetail: "",
SubAppid: "",
Chnlstoreid: "666667",
Subbranch: "",
Idno: "",
Extendparams: "",
Truename: "",
Asinfo: "",
Fqnum: "",
NotifyUrl: "https://www.callback.com/tonglian/onlinePay",
Signtype: "RSA",
Unpid: "",
Sign: "",
Terminfo: "",
Operatorid: "",
}
terminfo := &TerminfoBase{
Termno: "N502F01147",
Devicetype: "10",
Termsn: "N502F01147",
Encryptrandnum: "",
Secrettext: "",
Appversion: "",
Longitude: "+121.48352",
Latitude: "-03.561345",
Deviceip: "",
}
terminfoBByte, _ := json.Marshal(terminfo)
param.Terminfo = string(terminfoBByte)
api.CreateOnlineBankOrder(param)
}
func TestRefreshPayStatus(t *testing.T) {
param := &PayTransactionStatusQuery{
//Orgid: "",
//Cusid: "",
//Appid: "",
//Version: "",
Reqsn: "202504221811",
Trxid: "",
Randomstr: utils.GetUUID(),
Signtype: "RSA",
Sign: "",
}
api.QueryPayTransaction(param)
}
func TestOrderRefund(t *testing.T) {
param := &OnLineOrderRefundParam{
Trxamt: utils.Int2Str(1),
Reqsn: "202504250924",
Oldreqsn: "202504221811",
Oldtrxid: "",
Remark: "测试退款",
Benefitdetail: "",
Randomstr: utils.GetUUID(),
Signtype: EncryptionRsa,
Sign: "",
}
_, _, err := api.OrderRefund(param)
fmt.Println(err)
}

View File

@@ -1,148 +1,14 @@
package tonglianpayapi
import (
"crypto/md5"
"fmt"
"net/http"
"sort"
"strings"
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
)
const (
prodURL = "https://vsp.allinpay.com/apiweb"
prodURL2 = "https://syb.allinpay.com/apiweb"
sepcAction = "unitorder/pay"
sepcAction2 = "h5unionpay/unionorder"
sigKey = "sign"
PayTypeWxXcx = "W06"
PayTypeWxCode = "W01"
PayTypeZfbApp = "A03"
PayTypeZfbQrcode = "A01"
PayTypeZfbJS = "A02"
PayTypeH5 = "H5"
ResponseCodeSuccess = "SUCCESS"
ResponseCodeFail = "FAIL"
)
type API struct {
appID string
cusID string
appKey string
client *http.Client
config *platformapi.APIConfig
}
type CreateUnitorderOrderParam struct {
CusID string `json:"cusid"`
AppID string `json:"appid"`
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
NotifyUrl string `json:"notifyUrl"` //接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。
Acct string `json:"acct"`
PayType string `json:"paytype"`
SubAppID string `json:"subAppID"`
}
type CreateUnitOrderOrderResult struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
CusID string `json:"cusID"`
AppID string `json:"appID"`
TrxID string `json:"trxID"`
ChnltrxID string `json:"chnltrxID"`
Reqsn string `json:"reqsn"`
RandomStr string `json:"randomStr"`
TrxStatus string `json:"trxStatus"`
FinTime string `json:"finTime"`
ErrMsg string `json:"errMsg"`
PayInfo string `json:"payInfo"`
Sign string `json:"sign"`
}
type PayInfo struct {
AppID string `json:"appID"`
TimeStamp string `json:"timeStamp"`
NonceStr string `json:"nonceStr"`
Package string `json:"package"`
SignType string `json:"signType"`
PaySign string `json:"paySign"`
}
type PayRefundParam struct {
CusID string `json:"cusid"`
AppID string `json:"appid"`
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
OldReqsn string `json:"oldReqsn"`
Remark string `json:"remark"`
RandomStr string `json:"randomStr"`
Sign string `json:"sign"`
TrxID string `json:"trxID"`
OldTrxID string `json:"oldTrxID"`
}
type PayRefundResult struct {
RetCode string `json:"retCode"`
RetMsg string `json:"retMsg"`
CusID string `json:"cusID"`
AppID string `json:"appID"`
TrxID string `json:"trxID"`
Reqsn string `json:"reqsn"`
TrxStatus string `json:"trxStatus"`
FinTime string `json:"finTime"`
ErrMsg string `json:"errMsg"`
RandomStr string `json:"randomStr"`
Sign string `json:"sign"`
Fee string `json:"fee"`
TrxCode string `json:"trxCode"`
}
type CreateH5UnitorderOrderParam struct {
Trxamt int `json:"trxamt"` //交易金额 单位为分
Reqsn string `json:"reqsn"` //商户交易单号
NotifyUrl string `json:"notifyUrl"` //接收微信支付异步通知回调地址通知url必须为直接可访问的url不能携带参数。
Charset string `json:"charset"`
Returl string `json:"returl"`
Body string `json:"body"`
}
func New(appID, appKey, cusID string, config ...*platformapi.APIConfig) *API {
curConfig := platformapi.DefAPIConfig
if len(config) > 0 {
curConfig = *config[0]
}
return &API{
appID: appID,
appKey: appKey,
cusID: cusID,
client: &http.Client{Timeout: curConfig.ClientTimeout},
config: &curConfig,
}
}
func (a *API) signParam(params map[string]interface{}) (sig string) {
var valueList []string
for k, v := range params {
if k != sigKey {
if str := fmt.Sprint(v); str != "" {
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
}
}
}
valueList = append(valueList, fmt.Sprintf("key=%s", a.appKey))
sort.Sort(sort.StringSlice(valueList))
sig = strings.Join(valueList, "&")
binSig := md5.Sum([]byte(sig))
sig = fmt.Sprintf("%X", binSig)
return sig
}
func (a *API) AccessAPI(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
params := make(map[string]interface{})
params["appid"] = a.appID

View File

@@ -58,3 +58,51 @@ func TestPayRefund(t *testing.T) {
OldTrxID: "122094350000087981",
})
}
//
//func TestMisPay(t *testing.T) {
//
// custData := &CustDataDetail{
// BusinessId: BusinessTypeBUSIORDERTRANSQR,
// Amount: "1",
// OrderNo: "202504171111",
// Memo: "",
// QrCode: "",
// TramsCheck: "",
// PageAppendContent: "",
// ValidateInfo: "",
// BusInfo: "",
// }
// param := &OnMisPayReq{
// AppId: api.appID,
// BusinessId: BusinessTypeBUSIORDERTRANSQR,
// CustData: "000000000002",
// CashId: "n502f01147",
// StoreId: "66666",
// SignData: "",
// AppPackageNm: "",
// AppClassNm: "",
// BusExtpara: "",
// }
// custByte, _ := json.Marshal(custData)
// param.CustData = string(custByte)
//
// api.CreateMisPayOrder(param, custData)
//}
//
//func TestSignMd5(t *testing.T) {
// custData := &CustDataDetail{
// BusinessId: "100000003",
// Amount: "000000000002",
// OrderNo: "123123213",
// Memo: "",
// QrCode: "",
// TramsCheck: "",
// PageAppendContent: "",
// ValidateInfo: "",
// BusInfo: "",
// }
// licence := `9a432306-b93d-4d0d-aa7d-ac2bb89dee25-20200208002855`
// sig := api.signMisParam("100000003", licence, custData)
// fmt.Println(sig)
//}

View File

@@ -0,0 +1,149 @@
package tonglianpayapi
//
//import (
// "crypto/md5"
// "fmt"
// "git.rosy.net.cn/baseapi/platformapi"
// "git.rosy.net.cn/baseapi/utils"
// "net/http"
// "strings"
//)
//
//const (
// TongLianMisPay = "https://cloudmiscash.allinpay.com/cloudMis-transaction" // 通联mis支付(基础收款用于一般无特殊支付业务需求的标准行业,如零售、餐饮类商户及场景)
// MisPayAction = "api/v2/process"
//)
//
//const (
// BusinessTypeBUSIORDERTRANS = "100000003" // 订单支付收款(不含查询流程)
// BusinessTypeBUSIORDERTRANSBANK = "100100003" // 订单支付银行卡收款(不含查询)
// BusinessTypeBUSIORDERTRANSQR = "100300003" // 订单支付扫码收款(不含查询)
// BusinessTypeBUSIORDERSALE = "100000002" // 订单支付收款(含查询流程)
// BusinessTypeBUSIORDERSALEBANK = "100100002" // 订单支付银行卡收款(含查询流程)
// BusinessTypeBUSIORDERSALEQR = "100300002" // 订单支付扫码收款(含查询流程)
//)
//
//func (a *API) signMisParam(businessID, licence string, custData *CustDataDetail) (sig string) {
// var signBuffer = new(strings.Builder)
// //signBuffer.Write([]byte(a.appID))
// signBuffer.Write([]byte("app_id_001"))
// signBuffer.Write([]byte(businessID))
// signBuffer.Write([]byte(fmt.Sprintf(`{"BUSINESS_ID":"%s","AMOUNT":"%s","ORDER_NO":"%s"}`, custData.BusinessId, custData.Amount, custData.OrderNo)))
// signBuffer.Write([]byte(licence))
// fmt.Println(signBuffer.String())
// binSig := md5.Sum([]byte(signBuffer.String()))
// sig = fmt.Sprintf("%x", binSig)
// return sig
//}
//
//func (a *API) AccessMisAPI(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
// //params := make(map[string]interface{})
// //params["APP_ID"] = a.appID
// ////params["randomstr"] = utils.GetUUID()
// ////params["version"] = "12"
// //params = utils.MergeMaps(params, bizParams)
// //signStr := a.signParam(params)
// //params["SIGN_DATA"] = signStr
// fullURL := utils.GenerateGetURL(TongLianMisPay, action, nil)
// err = platformapi.AccessPlatformAPIWithRetry(a.client,
// func() *http.Request {
// 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")
// 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["RSP_CODE"])
// if returnCode != MisStatusSuccess {
// errLevel = platformapi.ErrLevelGeneralFail
// err = utils.NewErrorCode(utils.Interface2String(jsonResult1["errmsg"])+utils.Interface2String(jsonResult1["retmsg"]), returnCode)
// }
// retVal = jsonResult1
// }
// return errLevel, err
// })
// return retVal, err
//}
//
//// CreateMisPayOrder 创建订单(扫码枪,扫二维码支付)
//func (a *API) CreateMisPayOrder(param *OnMisPayReq, custData *CustDataDetail) (err error) {
// param.AppId = a.appID
// param.SignData = a.signMisParam(param.BusinessId, "", custData)
// params := utils.Struct2MapByJson(param)
// result, err := a.AccessMisAPI(MisPayAction, params)
// fmt.Println(result)
// return
//}
//
//type OnMisPayReq struct {
// AppId string `json:"APP_ID"` // 必填 应用分配ID
// BusinessId string `json:"BUSINESS_ID"` // 必填 业务类型
// CustData string `json:"CUST_DATA"` // 必填 具体的支付请求数据JSON格式字符串
// CashId string `json:"CASH_ID"` // 必填 收银机款台号
// StoreId string `json:"STORE_ID"` // 必填 商户分店号
// SignData string `json:"SIGN_DATA"` // 必填 计算方法参照附录1
// AppPackageNm string `json:"APP_PACKAGE_NM"` // 非必填 指定APP包名
// AppClassNm string `json:"APP_CLASS_NM"` // 非必填 指定类名
// BusExtpara string `json:"BUS_EXTPARA"` // 非必填 业务扩展字段用于特定功能详见附录2
//}
//type CustDataDetail struct {
// BusinessId string `json:"BUSINESS_ID"` // 必填 业务类型
// Amount string `json:"AMOUNT"` // 必填 支付金额,十二位长度(单位:分,不足左补零)
// OrderNo string `json:"ORDER_NO"` // 必填 订单编号
// Memo string `json:"MEMO"` // 非必填 订单编号
// QrCode string `json:"QRCODE"` // 非必填 订单编号
// TramsCheck string `json:"TRANS_CHECK"` // 非必填 订单编号
// PageAppendContent string `json:"PAGE_APPEND_CONTENT"` // 非必填 订单编号
// ValidateInfo string `json:"VALIDATE_INFO"` // 非必填 订单编号
// BusInfo string `json:"BUS_INFO"` // 非必填 订单编号
//}
//
//type MisPayResp struct {
// RspCode string `json:"RSP_CODE"` // 云MIS系统服务调用返回码 支付返回代码请参考RSP_DATA里支付结果字段
// RspData string `json:"RSP_DATA"` // 透传支付产品给云MIS的响应JSON字符串
// RspDesc string `json:"RSP_DESC"` // 交易级返回描述
// CloudMisTrxSsn string `json:"ClOUD_MIS_TRX_SSN"` // 交易成功返回云MIS系统唯一流水号用于查询或对账
//}
//
//type MisPayRspData struct {
// BusinessId string `json:"BUSINESS_ID"` // 必填 业务类型
// RejCode string `json:"REJCODE"` // 交易返回码
// RejCodeCn string `json:"REJCODE_CN"` // 交易返回码注释
// Cups string `json:"CUPS"` // 卡组织,银行卡为空 (ALP支付宝 WXP微信支付)
// MerchID string `json:"MERCH_ID"` // 商户编号
// TerID string `json:"TER_ID"` // 终端编号
// MerchName string `json:"MERCH_NAME"` // 商户名称
// BatchNo string `json:"BATCH_NO"` // 批次号
// TraceNo string `json:"TRACE_NO"` // 凭证号
// TransTicketNo string `json:"TRANS_TICKET_NO"` // 交易单号
// OrderNo string `json:"order_no"` // 订单编号
// Amount string `json:"AMOUNT"` // 支付金额,十二位长度(单位:分)
// RefNo string `json:"REF_NO"` // 系统参考号
// CarDno string `json:"CARDNO"` // 银行卡交易时返回卡号扫码交易返回OPENID或USERID
// CardTypeIdenty string `json:"CARD_TYPE_IDENTY"` // 借贷记卡标识(银行卡) 0:借记 1:贷记
// WildCardSign string `json:"WILD_CARD_SIGN"` //内外卡标识(银行卡) 0内卡 1:外卡
// ExpDate string `json:"EXP_DATE"` // 有效期
// Date string `json:"DATE"` // 支付日期
// Time string `json:"TIME"` // 支付时间
// PrintFlag string `json:"PRINT_FLAG"` // 是否打印小票1打印,0未打印
// CardFee string `json:"CARD_FEE"` // 手续费,十二位长度(单位:分)
// TransCheck string `json:"TRANS_CHECK"` // 交易唯一标识
// AuthNo string `json:"AUTH_NO"` // 授权码
// Sign string `json:"SIGN"` // 签名
// CardType string `json:"CARDTYPE"` // 卡类型
// TransChannel string `json:"TRANS_CHANNEL"` // 交易渠道
// IssNo string `json:"ISS_NO"` // 发卡行行号
// IssName string `json:"ISS_NAME"` // 发卡行名称
// Memo string `json:"MEMO"` // 备注信息
// PrtCommon string `json:"PRT_COMMON"` // 打印内容公共部分(仅用于简易终端版)
// PrtCardholder string `json:"PRT_CARDHOLDER"` // 打印内容持卡人联部分(仅用于简易终端版)
// PrtMerchant string `json:"PRT_MERCHANT"` // 打印内容商户联部分(仅用于简易终端版)
// DiscAmount string `json:"DISC_AMOUNT"` // 优惠金额
// ActuallyAmount string `json:"ACTUALLY_AMOUNT"` // 实付金额
//}