diff --git a/platformapi/tonglianpayapi/callback.go b/platformapi/tonglianpayapi/callback.go new file mode 100644 index 00000000..4c3ec645 --- /dev/null +++ b/platformapi/tonglianpayapi/callback.go @@ -0,0 +1 @@ +package tonglianpayapi diff --git a/platformapi/tonglianpayapi/callback_test.go b/platformapi/tonglianpayapi/callback_test.go new file mode 100644 index 00000000..4c3ec645 --- /dev/null +++ b/platformapi/tonglianpayapi/callback_test.go @@ -0,0 +1 @@ +package tonglianpayapi diff --git a/platformapi/tonglianpayapi/tonglianpayapi.go b/platformapi/tonglianpayapi/tonglianpayapi.go new file mode 100644 index 00000000..ebb3e269 --- /dev/null +++ b/platformapi/tonglianpayapi/tonglianpayapi.go @@ -0,0 +1,144 @@ +package tonglianpayapi + +import ( + "crypto/md5" + "fmt" + "net/http" + "sort" + "strings" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/platformapi" + "git.rosy.net.cn/baseapi/utils" +) + +const ( + prodURL = "https://vsp.allinpay.com/apiweb" + sepcAction = "unitorder/pay" + + sigKey = "sign" + payType = "W06" + + ResponseCodeSuccess = "SUCCESS" + ResponseCodeFail = "FAIL" +) + +type API struct { + appID string + cusID string + appKey string + subAppid 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"` +} + +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"` +} + +func New(appID, appKey, cusID, subAppid string, config ...*platformapi.APIConfig) *API { + curConfig := platformapi.DefAPIConfig + if len(config) > 0 { + curConfig = *config[0] + } + return &API{ + appID: appID, + appKey: appKey, + cusID: cusID, + subAppid: subAppid, + 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 + params["cusid"] = a.cusID + params["randomstr"] = utils.GetUUID() + params["version"] = "12" + params = utils.MergeMaps(params, bizParams) + if action == sepcAction { + params["paytype"] = payType + params["sub_appid"] = a.subAppid + signStr := a.signParam(params) + params["sign"] = signStr + } + fullURL := utils.GenerateGetURL(prodURL, action, nil) + + err = platformapi.AccessPlatformAPIWithRetry(a.client, + func() *http.Request { + request, _ := http.NewRequest(http.MethodPost, fullURL, 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 != ResponseCodeSuccess { + errLevel = platformapi.ErrLevelGeneralFail + err = utils.NewErrorCode(utils.Interface2String(jsonResult1["retmsg"]), returnCode) + baseapi.SugarLogger.Debugf("tonglianpay AccessAPI failed, jsonResult1:%s", utils.Format4Output(jsonResult1, true)) + } + retVal = jsonResult1 + } + return errLevel, err + }) + return retVal, err +} + +func (a *API) CreateUnitorderOrder(param *CreateUnitorderOrderParam) (result *CreateUnitorderOrderResult, err error) { + params := make(map[string]interface{}) + params["trxamt"] = param.Trxamt + params["notify_url"] = param.NotifyUrl + params["reqsn"] = param.Reqsn + params["acct"] = param.Acct + retVal, err := a.AccessAPI(sepcAction, params) + if err == nil { + utils.Map2StructByJson(retVal, &result, false) + } + return result, err +} diff --git a/platformapi/tonglianpayapi/tonglianpayapi_test.go b/platformapi/tonglianpayapi/tonglianpayapi_test.go new file mode 100644 index 00000000..57f66a9c --- /dev/null +++ b/platformapi/tonglianpayapi/tonglianpayapi_test.go @@ -0,0 +1,35 @@ +package tonglianpayapi + +import ( + "testing" + + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/utils" + "go.uber.org/zap" +) + +var ( + api *API + sugarLogger *zap.SugaredLogger +) + +func init() { + logger, _ := zap.NewDevelopment() + sugarLogger = logger.Sugar() + baseapi.Init(sugarLogger) + + api = New("00183083", "18048531223", "56065105499TVAH", "wx4b5930c13f8b1170") +} + +func TestCreateUnitorderOrder(t *testing.T) { + result, err := api.CreateUnitorderOrder(&CreateUnitorderOrderParam{ + Reqsn: "88320316370927", + Trxamt: 10, + NotifyUrl: "http://callback.test.jxc4.com/tlpay/msg/", + Acct: "ojWb10M_8kV8NT0aZJa6A5umG1c8", + }) + if err != nil { + t.Fatal(err) + } + t.Log(utils.Format4Output(result, false)) +}