SoFunction
Updated on 2025-03-02

Golang implements JD Payment v2 version sample code

1. Preparation phase

pc&h5 access steps

Official Document /docList...

View the main access steps

Key generation

• Desc key needs to be set

• md5 key and app id app docking will be used

• Certificate file name

my_rsa_private_pkcs8_key.pem
wy_rsa_public_key.pem

The sample program uses the private key format as pkcs8 format

The data in the official SDK can be used in the sample program

Download SDK address /docList...

Find the demo in the interface document

Packages that will be used

import (
  "encoding/base64"
  "encoding/json"
  "encoding/xml"
  "errors"
  "fmt"
  "io/ioutil"
  "net/http"
  "os"
  "strconv"
  "strings"
  "time"
)

Encrypt, decrypt, verify signature

package main
import (
  "bytes"
  "crypto"
  "crypto/des"
  cryptoRand "crypto/rand"
  "crypto/rsa"
  "crypto/sha256"
  "crypto/x509"
  "encoding/base64"
  "encoding/hex"
  "encoding/pem"
  "errors"
  "fmt"
  "math/rand"
  "regexp"
  "sort"
  "strings"
  "time"
)
func randNumber() string {
  return ("%05v", ((().UnixNano())).Int31n(100000))
}
func checkSign(decryptBytes []byte, sign, publicKey string) bool {
  decrypt := string(decryptBytes)
  clipStartIndex := (decrypt, "<sign>")
  clipEndIndex := (decrypt, "</sign>")
  xmlStart := decrypt[0:clipStartIndex]
  xmlEnd := decrypt[clipEndIndex+7 : len(decrypt)]
  originXml := xmlStart + xmlEnd
  //Signature verification  if sign == "" {
    return false
  }
  return checkRsaSign(originXml, publicKey, sign)
}
func replaceXmlStrBlankChar(str string) string {
  str = (str, "\r", "", -1)
  str = (str, "\n", "", -1)
  str = (str, "\t", "", -1)
  reg, _ := (">\\s+<")
  str = (str, "><")
  reg, _ = ("\\s+\\/>")
  str = (str, "/>")
  return str
}
func getPaySign(paramMap map[string]string, privateKey string) (string, error) {
  payString := getSortString(paramMap)
  return getRsaSign(payString, privateKey)
}
// ------
// Encryptionfunc encrypt3DES(paramMap map[string]string, desKey string) (map[string]string, error) {
  desKey = base64DecodeStr(desKey)
  for k, v := range paramMap {
    if k == "sign" || k == "merchant" || k == "version" {
      continue
    }
    encrypt, err := tripleEcbDesEncrypt([]byte(v), []byte(desKey))
    if err != nil {
      return paramMap, err
    }
    paramMap[k] = decimalByteSlice2HexString(encrypt)
  }
  return paramMap, nil
}
func decryptArg(notifyQuery NotifyQuery, desKey string) (decryptBytes []byte, err error) {
  desKeyBytes, err := (desKey)
  if err != nil {
    return nil, err
  }
  encryptBytes, err := ()
  if err != nil {
    return nil, err
  }
  encryptBytes, err = hexString2Bytes(string(encryptBytes))
  if err != nil {
    return nil, err
  }
  decryptBytes, err = tripleEcbDesDecrypt(encryptBytes, desKeyBytes)
  if err != nil {
    return nil, err
  }
  return decryptBytes, nil
}
// JDAPP fill rulesfunc jdPadding(origData []byte) []byte {
  merchantData := len(origData)
  x := (merchantData + 4) % 8
  y := 0
  if x == 0 {
    y = 0
  } else {
    y = 8 - x
  }
  sizeByte := integerToBytes(merchantData)
  var resultByte []byte
  //Fill in byte data length  for i := 0; i < 4; i++ {
    resultByte = append(resultByte, sizeByte[i])
  }
  //Fill in the original data length  for j := 0; j < merchantData; j++ {
    resultByte = append(resultByte, origData[j])
  }
  //Fill 0  for k := 0; k < y; k++ {
    resultByte = append(resultByte, 0x00)
  }
  return resultByte
}
func jdUnPadding(unPaddingResult []byte) []byte {
  var Result []byte
  var dataSizeByte []byte
  for i := 0; i < 4; i++ {
    dataSizeByte = append(dataSizeByte, unPaddingResult[i])
  }
  decimalDataSize := byteArrayToInt(dataSizeByte)
  for j := 0; j < decimalDataSize; j++ {
    Result = append(Result, unPaddingResult[4+j])
  }
  return Result
}
// The actual length represented by the byte arrayfunc byteArrayToInt(dataSizeByte []byte) int {
  value := 0
  for i := 0; i < 4; i++ {
    shift := byte((4 - 1 - i) * 8)
    value = value + int(dataSizeByte[i]&0x000000FF)<<shift
  }
  return value
}
func integerToBytes(val int) [4]byte {
  byt := [4]byte{}
  byt[0] = byte(val >> 24 & 0xff)
  byt[1] = byte(val >> 16 & 0xff)
  byt[2] = byte(val >> 8 & 0xff)
  byt[3] = byte(val & 0xff)
  return byt
}
// byte to hexadecimal stringfunc decimalByteSlice2HexString(DecimalSlice []byte) string {
  var sa = make([]string, 0)
  for _, v := range DecimalSlice {
    sa = append(sa, ("%02X", v))
  }
  ss := (sa, "")
  return ss
}
// Hexadecimal string to bytefunc hexString2Bytes(str string) ([]byte, error) {
  Bys, err := (str)
  if err != nil {
    return nil, err
  }
  return Bys, nil
}
// base decodingfunc base64DecodeStr(src string) string {
  a, err := (src)
  if err != nil {
    return ""
  }
  return string(a)
}
// Des decryptionfunc decrypt(crypted, key []byte) ([]byte, error) {
  if len(crypted) < 1 || len(key) < 1 {
    return nil, ("wrong data or key")
  }
  block, err := (key)
  if err != nil {
    return nil, err
  }
  out := make([]byte, len(crypted))
  dst := out
  bs := ()
  if len(crypted)%bs != 0 {
    return nil, ("wrong crypted size")
  }
  for len(crypted) > 0 {
    (dst, crypted[:bs])
    crypted = crypted[bs:]
    dst = dst[bs:]
  }
  return out, nil
}
// [golang ECB 3DES Decrypt]
func tripleEcbDesDecrypt(crypted, key []byte) ([]byte, error) {
  tkey := make([]byte, 24, 24)
  copy(tkey, key)
  k1 := tkey[:8]
  k2 := tkey[8:16]
  k3 := tkey[16:]
  buf1, err := decrypt(crypted, k3)
  if err != nil {
    return nil, err
  }
  buf2, err := encrypt(buf1, k2)
  if err != nil {
    return nil, err
  }
  out, err := decrypt(buf2, k1)
  if err != nil {
    return nil, err
  }
  out = jdUnPadding(out)
  return out, nil
}
// sha256 encryptionfunc hasha256(str string) string {
  h := ()
  ([]byte(str))
  cipherStr := (nil)
  //return cipherStr
  return (cipherStr)
}
// Base decodingfunc base64EncodeStr(src string) string {
  return ([]byte(src))
}
// Digitally sign the hash value of the messagefunc signPKCS1v15(msg, privateKey []byte, hashType ) ([]byte, error) {
  block, _ := (privateKey)
  if block == nil {
    return nil, ("private key format error")
  }
  pri, err := x509.ParsePKCS8PrivateKey()
  if err != nil {
    return nil, ("parse private key error")
  }
  key, ok := pri.(*)
  if ok == false {
    return nil, ("private key format error")
  }
  sign, err := rsa.SignPKCS1v15(, key, hashType, msg)
  if err != nil {
    return nil, ("sign error")
  }
  return sign, nil
}
// Des encryptionfunc encrypt(origData, key []byte) ([]byte, error) {
  if len(origData) < 1 || len(key) < 1 {
    return nil, ("wrong data or key")
  }
  block, err := (key)
  if err != nil {
    return nil, err
  }
  bs := ()
  if len(origData)%bs != 0 {
    return nil, ("wrong padding")
  }
  out := make([]byte, len(origData))
  dst := out
  for len(origData) > 0 {
    (dst, origData[:bs])
    origData = origData[bs:]
    dst = dst[bs:]
  }
  return out, nil
}
// [golang ECB 3DES Encrypt]
func tripleEcbDesEncrypt(origData, key []byte) ([]byte, error) {
  tkey := make([]byte, 24, 24)
  copy(tkey, key)
  k1 := tkey[:8]
  k2 := tkey[8:16]
  k3 := tkey[16:]
  origData = jdPadding(origData) // PKCS5Padding(origData, bs)
  buf1, err := encrypt(origData, k1)
  if err != nil {
    return nil, err
  }
  buf2, err := decrypt(buf1, k2)
  if err != nil {
    return nil, err
  }
  out, err := encrypt(buf2, k3)
  if err != nil {
    return nil, err
  }
  return out, nil
}
// ------------
// Verify the signaturefunc verifyPKCS1v15(msg, sign, publicKey []byte, hashType ) bool {
  block, _ := (publicKey)
  if block == nil {
    return false
  }
  pub, err := ()
  if err != nil {
    panic(err)
  }
  err = rsa.VerifyPKCS1v15(pub.(*), hashType, msg, sign)
  return err == nil
}
func getRsaSign(paramStr string, privateKey string) (string, error) {
  sha256Str := hasha256(paramStr)
  sign, err := signPKCS1v15([]byte(sha256Str), []byte(privateKey), (0))
  if err != nil {
    return "", err
  }
  base64String := (sign)
  return base64String, nil
}
func checkRsaSign(paramStr string, publicKey, sign string) bool {
  signByte, err := (sign)
  if err != nil {
    return false
  }
  sha256Str := hasha256(paramStr)
  return verifyPKCS1v15([]byte(sha256Str), signByte, []byte(publicKey), (0))
}
// -------
// String stitching// Payment string stitchingfunc getSortString(m map[string]string) string {
  var buf 
  keys := make([]string, 0, len(m))
  for k := range m {
    keys = append(keys, k)
  }
  (keys)
  for _, k := range keys {
    vs := m[k]
    if () > 0 {
      ('&')
    }
    (k)
    ('=')
    (vs)
  }
  return ()
}

Loading the key in the program

func getKey(keyType string) (string, error) {
  keyMap := map[string]string{
    "private_key": "./",
    "public_key": "./",
  }
  path, ok := keyMap[keyType]
  if !ok {
    return "", ("key path not exists")
  }
  fileHandler, err := (path)
  if err != nil {
    return "", err
  }
  defer ()
  keyBytes, err := (fileHandler)
  if err != nil {
    return "", err
  }
  return string(keyBytes), nil
}

2. Initiate payment

constant

constant
const version = "V2.0" // JD Payment Versionconst merchantId = "" // Merchant IDconst desKey = ""   // desc key
const timeLayout = "20060102150405"
const cny = "CNY"
const practicalityGoodsType = "GT01" //Product type-Practical itemconst businessServiceConsumeCode = "100001"
const practicality = "0" //Product Type-Real things

Call online payment interface

pc h5 initiates payment

Official Document /docList...

type Order struct {
  OrderId     string        `json:"order_id"`
  Amount     float64        `json:"amount"`
  Items      []*OrderItem     `json:"items"`
  ShippingAddress *OrderShippingAddress `json:"shipping_address"`
}
type OrderItem struct {
  GoodsNo  string `json:"goods_no"`
  GoodsName string `json:"goods_name"`
  GoodsPrice float64 `json:"goods_price"`
  GoodsNum  uint32 `json:"goods_num"`
}
type OrderShippingAddress struct {
  Name   string `json:"name"`
  Mobile  string `json:"mobile"`
  Address string `json:"address"`
  Province string `json:"province"`
  City   string `json:"city"`
  Country string `json:"country"`
}
type ReqWithEncrypt struct {
  XMLName  `xml:"jdpay" json:"-"`
  Version string  `xml:"version" json:"version"`  //Version  Merchant string  `xml:"merchant" json:"merchant"` //Merchant number  Encrypt string  `xml:"encrypt" json:"encrypt"`  //Encrypted data}
const version = "V2.0" // JD Payment Versionconst merchantId = "22294531"
const desKey = "ta4E/aspLA3lgFGKmNDNRYU92RkZ4w2t"
const timeLayout = "20060102150405"
const cny = "CNY"
const practicalityGoodsType = "GT01" //Product type-Practical itemconst businessServiceConsumeCode = "100001"
const practicality = "0" //Product type-Practical itemtype GoodsInfo struct {
  Id  string `json:"id"`  //Product number  Name string `json:"name"` //Product name  Price int64 `json:"price"` //Unit price of goods, unit segment  Num  uint32 `json:"num"`  //Product quantity  Type string `json:"type"` //Product Type}
type ReceiverInfo struct {
  Name   string `json:"name"`
  Address string `json:"address"`
  Mobile  string `json:"mobile"`
  Province string `json:"province"`
  City   string `json:"city"`
  Country string `json:"country"`
}
type KjInfo struct {
  GoodsSubmittedCustoms string `json:"goodsSubmittedCustoms"` // Whether to declare customs Y/N  GoodsUnderBonded   string `json:"goodsUnderBonded"`   // Whether to pay under bonded goods Y/N}
const jdPayUrl = "/jdpay/saveOrder"
// pc h5 form form submission paymentfunc postFormPay(arg Order) (payStr string, err error) {
  // Payment parameters  paramMap := make(map[string]string)
  amountStr := ("%.f", *100)
  totalFee, err := (amountStr, 10, 64)
  if err != nil {
    return payStr, err
  }
  var goodsInfos []GoodsInfo
  for _, v := range  {
    priceStr := ("%.f", *100)
    price, err := (priceStr, 10, 64)
    if err != nil {
      return payStr, err
    }
    goodsInfos = append(goodsInfos, GoodsInfo{
      Id:  ,
      Name: ,
      Price: price,
      Num:  ,
      Type: practicalityGoodsType, // Product Type - Real Item    })
  }
  goodsInfoBytes, _ := (goodsInfos)
  kjInfo := KjInfo{GoodsSubmittedCustoms: "N", GoodsUnderBonded: "N"}
  kjInfoBytes, _ := (kjInfo)
  detailAddress :=  +  +  + 
  receiverInfo := ReceiverInfo{
    Name:   ,   // Name of the consignee    Mobile:  ,  // Consignee's mobile phone number    Address: detailAddress,        // The address requires that it passes through provinces, cities and districts    Province: , // Province    City:   ,   // city    Country: , // district  }
  receiverInfoBytes, _ := (receiverInfo)
  orderId := ("test%s%s", ().Format("20060102150405"), randNumber())
  paramMap["version"] = version
  paramMap["merchant"] = merchantId
  paramMap["tradeNum"] = orderId  // Order number  paramMap["tradeName"] = orderId // Order description  paramMap["tradeDesc"] = orderId // Order description  paramMap["payMerchant"] = "test" // Merchant name  paramMap["tradeTime"] = ().Format(timeLayout)
  paramMap["amount"] = ("%v", totalFee)
  paramMap["orderType"] = practicality
  paramMap["currency"] = cny
  paramMap["userId"] = "100"
  paramMap["expireTime"] = "3600" //Order expiration time, unit seconds  paramMap["goodsInfo"] = string(goodsInfoBytes)
  paramMap["settleCurrency"] = cny
  paramMap["kjInfo"] = string(kjInfoBytes)
  paramMap["bizTp"] = businessServiceConsumeCode
  paramMap["notifyUrl"] = "/notify"
  paramMap["callbackUrl"] = "/verify"
  paramMap["receiverInfo"] = string(receiverInfoBytes)
  // Certificate  privateKey, err := getKey("private_key")
  if err != nil {
    return payStr, err
  }
  // sign  paramMap["sign"], err = getPaySign(paramMap, privateKey)
  if err != nil {
    return payStr, err
  }
  // Data encryption  paramMap, err = encrypt3DES(paramMap, desKey)
  if err != nil {
    return payStr, err
  }
  // Splice payment form  payStr = "<form action='" + jdPayUrl + "' method='post' id='pay_form'>"
  for k, v := range paramMap {
    payStr += "<input value='" + v + "' name='" + k + "' type='hidden'/>"
  }
  payStr += "</form>"
  payStr += "<script>var form = ('pay_form');()</script>"
  return payStr, nil
}

3. Asynchronous notification

Data decryption, signature verification

// Decrypt asynchronous notification informationtype NotifyQuery struct {
  XMLName    `xml:"jdpay" json:"-"`
  Version string    `xml:"version" json:"version"`  // Version number  Merchant string    `xml:"merchant" json:"merchant"` // Merchant number  Result  NotifyResult `xml:"result" json:"result"`   // Transaction results  Encrypt string    `xml:"encrypt" json:"encrypt"`  // Encrypted information}
type NotifyDecrypt struct {
  XMLName     `xml:"jdpay" json:"-"`
  Version  string    `xml:"version" json:"version"`   // Version number  Merchant string    `xml:"merchant" json:"merchant"`  // Merchant number  Result  NotifyResult `xml:"result" json:"result"`    // Transaction results  TradeNum string    `xml:"tradeNum" json:"tradeNum"`  // Order number  TradeType int      `xml:"tradeType" json:"tradeType"` // Transaction type  Sign   string    `xml:"sign" json:"sign"`      // Data signature  Amount  int64     `xml:"amount" json:"amount"`    // Total amount of RMB payment  OrderId  string    `json:"order_id"`         // JD.com transaction flow number  Status  string    `xml:"status" json:"status"`    // Transaction status  PayList  NotifyPayList `xml:"payList" json:"payList"`   // Payment method details}
type NotifyResult struct {
  Code string `xml:"code" json:"code"` // Transaction return code  Desc string `xml:"desc" json:"desc"` // Return code information}
type NotifyPayList struct {
  Pay []NotifyPay `xml:"pay" json:"pay"`
}
type NotifyPay struct {
  PayType  int  `xml:"payType" json:"payType"`   // Payment method  Amount  int64 `xml:"amount" json:"amount"`    // Transaction amount  Currency string `xml:"currency" json:"currency"`  // Trading currency  TradeTime string `xml:"tradeTime" json:"tradeTime"` // Trading time}
// Decrypt asynchronous notification informationfunc notifyDataDecrypt(rawPost string) (notifyDecrypt NotifyDecrypt, err error) {
  // Analyze the encrypted payment institution parameters as structure  var notifyQuery NotifyQuery
  err = ([]byte(rawPost), &notifyQuery)
  if err != nil {
    return notifyDecrypt, err
  }
  // Decrypt the payment institution parameters  decryptBytes, err := decryptArg(notifyQuery, desKey)
  if err != nil {
    return notifyDecrypt, err
  }
  // The parameters of the decrypted payment institution are structured  err = (decryptBytes, &notifyDecrypt)
  if err != nil {
    return notifyDecrypt, err
  }
  // Certificate  publicKey, err := getKey("public_key")
  if err != nil {
    return notifyDecrypt, err
  }
  // Verify signature  if !checkSign(decryptBytes, , publicKey) {
    return notifyDecrypt, err
  }
  return notifyDecrypt, nil
}

4. Transaction inquiry

Inquiry of orders

type SearchWithoutSignRequest struct {
  XMLName   `xml:"jdpay" json:"-"`
  Version  string  `xml:"version" json:"version"`   // Version  Merchant string  `xml:"merchant" json:"merchant"`  // Merchant number  TradeNum string  `xml:"tradeNum" json:"tradeNum"`  // Order number  OTradeNum string  `xml:"oTradeNum" json:"oTradeNum"` // Original transaction number  TradeType string  `xml:"tradeType" json:"tradeType"` // Transaction type}
type SearchWithSignRequest struct {
  XMLName   `xml:"jdpay" json:"-"`
  Version  string  `xml:"version" json:"version"`   // Version  Merchant string  `xml:"merchant" json:"merchant"`  // Merchant number  TradeNum string  `xml:"tradeNum" json:"tradeNum"`  // Order number  OTradeNum string  `xml:"oTradeNum" json:"oTradeNum"` // Original transaction number  TradeType string  `xml:"tradeType" json:"tradeType"` // Transaction type  Sign   string  `xml:"sign" json:"sign"`      // sign}
type SearchResult struct {
  XMLName     `xml:"jdpay" json:"-"`
  Version string     `xml:"version" json:"version"`  // Version number  Merchant string     `xml:"merchant" json:"merchant"` // Merchant number  Result  SearchResultRsp `xml:"result" json:"result"`   // Transaction results  Encrypt string     `xml:"encrypt" json:"encrypt"`  // Encrypted information}
type SearchResultRsp struct {
  Code string `xml:"code" json:"code"` // Transaction return code  Desc string `xml:"desc" json:"desc"` // Return code information}
type SearchDecryptRsp struct {
  XMLName       `xml:"jdpay" json:"-"`
  Merchant string      `xml:"merchant" json:"merchant"`  // Merchant number  TradeNum string      `xml:"tradeNum" json:"tradeNum"`  // Order number  TradeType string      `xml:"tradeType" json:"tradeType"` // Transaction type  Result  SearchResultRsp `xml:"result" json:"result"`    // Transaction results  Sign   string      `xml:"sign" json:"sign"`      // Data signature  Amount  int64      `xml:"amount" json:"amount"`    // Total amount of RMB payment  Status  string      `xml:"status" json:"status"`    // Transaction status  PayList  SearchPayListRsp `xml:"payList" json:"payList"`   // Payment method details}
type SearchPayListRsp struct {
  Pay []SearchPayRsp `xml:"pay" json:"pay"`
}
type SearchPayRsp struct {
  PayType  int  `xml:"payType" json:"payType"`   // Payment method  Amount  int64 `xml:"amount" json:"amount"`    // Transaction amount  Currency string `xml:"currency" json:"currency"`  // Trading currency  TradeTime string `xml:"tradeTime" json:"tradeTime"` // Trading time}
const tradeWayUrl = "/service/query"
const customTradeType = "0" // Transaction typeconst successCode = "000000"
func searchTrade(orderId string) (searchDecryptRsp SearchDecryptRsp, err error) {
  searchWithoutSignRequest := SearchWithoutSignRequest{
    Version:  version,
    Merchant: merchantId,
    TradeNum: orderId,
    OTradeNum: "",
    TradeType: customTradeType,
  }
  xmlBytes, err := (searchWithoutSignRequest)
  xmlStr :=  + string(xmlBytes)
  xmlStr = replaceXmlStrBlankChar(xmlStr)
  // Certificate  privateKey, err := getKey("private_key")
  if err != nil {
    return searchDecryptRsp, err
  }
  // sign  sign, err := getRsaSign(xmlStr, privateKey)
  if err != nil {
    return searchDecryptRsp, err
  }
  searchWithSignRequest := SearchWithSignRequest{
    Version:  ,
    Merchant: ,
    TradeNum: ,
    OTradeNum: ,
    TradeType: ,
    Sign:   sign,
  }
  xmlBytes, err = (searchWithSignRequest)
  xmlStr = (, "\n") + string(xmlBytes)
  desKeyBytes, err := (desKey)
  if err != nil {
    return searchDecryptRsp, err
  }
  encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes)
  if err != nil {
    return searchDecryptRsp, err
  }
  reqEncrypt := decimalByteSlice2HexString(encryptBytes)
  reqEncrypt = ([]byte(reqEncrypt))
  searchWithEncrypt := ReqWithEncrypt{
    Version: version,
    Merchant: merchantId,
    Encrypt: reqEncrypt,
  }
  xmlBytes, err = (searchWithEncrypt)
  if err != nil {
    return searchDecryptRsp, err
  }
  xmlStr = (, "\n") + string(xmlBytes)
  request, err := (, tradeWayUrl, (xmlStr))
  if err != nil {
    return searchDecryptRsp, err
  }
  ("content-type", "application/xml; charset=utf-8")
  client := 
  response, err := (request)
  if err != nil {
    return searchDecryptRsp, err
  }
  defer ()
  bodyBytes, err := ()
  if err != nil {
    return searchDecryptRsp, err
  }
  searchResult := new(SearchResult)
  if err = (bodyBytes, searchResult); err != nil {
    return searchDecryptRsp, err
  }
  if  != successCode {
    return searchDecryptRsp, ()
  }
  // Decrypt the data  rspEncryptBytes, err := ()
  rspEncryptBytes, err = hexString2Bytes(string(rspEncryptBytes))
  if err != nil {
    return searchDecryptRsp, err
  }
  rspDecryptBytes, err := tripleEcbDesDecrypt(rspEncryptBytes, desKeyBytes)
  if err != nil {
    return searchDecryptRsp, err
  }
  err = (rspDecryptBytes, &searchDecryptRsp)
  if err != nil {
    return searchDecryptRsp, err
  }
  // Certificate  publicKey, err := getKey("public_key")
  if err != nil {
    return searchDecryptRsp, err
  }
  // Verify signature  if !checkSign(rspDecryptBytes, , publicKey) {
    return searchDecryptRsp, err
  }
  return searchDecryptRsp, nil
}

5. Apply for a refund

Apply for a refund

// Refundtype Refund struct {
  Merchant  string `json:"merchant"`
  TradeNum  string `json:"tradeNum"`
  OTradeNum string `json:"oTradeNum"`
  Amount   uint64 `json:"amount"`
  Currency  string `json:"currency"`
  DesKey   string `json:"desKey"`
  PublicKey string `json:"publicKey"`
  PrivateKey string `json:"privateKey"`
}
type RefundReqWithoutSign struct {
  XMLName   `xml:"jdpay" json:"-"`
  Version  string  `xml:"version" json:"version"`
  Merchant string  `xml:"merchant" json:"merchant"`
  TradeNum string  `xml:"tradeNum" json:"tradeNum"`
  OTradeNum string  `xml:"oTradeNum" json:"oTradeNum"`
  Amount  uint64  `xml:"amount" json:"amount"`
  Currency string  `xml:"currency" json:"currency"`
}
type RefundReqWithSign struct {
  XMLName   `xml:"jdpay" json:"-"`
  Version  string  `xml:"version" json:"version"`
  Merchant string  `xml:"merchant" json:"merchant"`
  TradeNum string  `xml:"tradeNum" json:"tradeNum"`
  OTradeNum string  `xml:"oTradeNum" json:"oTradeNum"`
  Amount  uint64  `xml:"amount" json:"amount"`
  Currency string  `xml:"currency" json:"currency"`
  Sign   string  `xml:"sign" json:"sign"`
}
type RefundResult struct {
  XMLName       `xml:"jdpay" json:"-"`
  Version string       `xml:"version" json:"version"`  // Version number  Merchant string       `xml:"merchant" json:"merchant"` // Merchant number  Result  RefundPayResultRsp `xml:"result" json:"result"`   // Refund results  Encrypt string       `xml:"encrypt" json:"encrypt"`  // Encrypted information}
type RefundPayResultRsp struct {
  Code string `xml:"code" json:"code"` // Transaction return code  Desc string `xml:"desc" json:"desc"` // Return code information}
type RefundPayDecryptRsp struct {
  XMLName        `xml:"jdpay" json:"-"`
  Version  string       `xml:"version" json:"version"`  // Version number  Merchant string       `xml:"merchant" json:"merchant"` // Merchant number  TradeNum string       `xml:"tradeNum" json:"tradeNum"`
  TradeType string       `xml:"tradeType"json:"tradeType"`
  Result  RefundPayResultRsp `xml:"result" json:"result"` // Refund results  Sign   string       `xml:"sign" json:"sign"`
  Amount  uint64       `xml:"amount" json:"amount"`
  Currency string       `xml:"currency" json:"currency"`
  TradeTime string       `xml:"tradeTime" json:"tradeTime"`
  Status  string       `xml:"status" json:"status"`
}
const refundGatewayUrl = "/service/refund"
// Apply for a refundfunc refundTrade(orderId string, amount float64) (refundPayDecryptRsp RefundPayDecryptRsp, err error) {
  totalFee, err := (("%.f", amount*100), 10, 64)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  refundReqWithoutSign := RefundReqWithoutSign{
    Version:  version,
    Merchant: merchantId,
    TradeNum: orderId + "-1",
    OTradeNum: orderId,
    Amount:  totalFee,
    Currency: cny,
  }
  xmlBytes, err := (refundReqWithoutSign)
  xmlStr :=  + string(xmlBytes)
  xmlStr = replaceXmlStrBlankChar(xmlStr)
  // Certificate  privateKey, err := getKey("private_key")
  if err != nil {
    return refundPayDecryptRsp, err
  }
  // sign  sign, err := getRsaSign(xmlStr, privateKey)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  refundReqWithSign := RefundReqWithSign{
    Version:  ,
    Merchant: ,
    TradeNum: ,
    OTradeNum: ,
    Amount:  ,
    Currency: ,
    Sign:   sign,
  }
  xmlBytes, err = (refundReqWithSign)
  xmlStr = (, "\n") + string(xmlBytes)
  desKeyBytes, err := (desKey)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  encryptBytes, err := tripleEcbDesEncrypt([]byte(xmlStr), desKeyBytes)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  reqEncrypt := decimalByteSlice2HexString(encryptBytes)
  reqEncrypt = ([]byte(reqEncrypt))
  refundReqWithEncrypt := ReqWithEncrypt{
    Version: version,
    Merchant: merchantId,
    Encrypt: reqEncrypt,
  }
  xmlBytes, err = (refundReqWithEncrypt)
  xmlStr = (, "\n") + string(xmlBytes)
  request, err := (, refundGatewayUrl, (xmlStr))
  if err != nil {
    return refundPayDecryptRsp, err
  }
  ("content-type", "application/xml; charset=utf-8")
  client := 
  response, err := (request)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  defer ()
  bodyBytes, err := ()
  if err != nil {
    return refundPayDecryptRsp, err
  }
  refundResult := new(RefundResult)
  if err = (bodyBytes, refundResult); err != nil {
    return refundPayDecryptRsp, err
  }
  // Decrypt the data  rspEncryptBytes, err := ()
  if err != nil {
    return refundPayDecryptRsp, err
  }
  rspEncryptBytes, err = hexString2Bytes(string(rspEncryptBytes))
  if err != nil {
    return refundPayDecryptRsp, err
  }
  rspDecryptBytes, err := tripleEcbDesDecrypt(rspEncryptBytes, desKeyBytes)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  err = (rspDecryptBytes, &refundPayDecryptRsp)
  if err != nil {
    return refundPayDecryptRsp, err
  }
  
  // Certificate  publicKey, err := getKey("public_key")
  if err != nil {
    return refundPayDecryptRsp, err
  }
  // Verify signature  if !checkSign(rspDecryptBytes, , publicKey) {
    return refundPayDecryptRsp, err
  }
  
  return refundPayDecryptRsp, nil
}

This is the article about golang implementing the JD Payment v2 version. For more related content on golang, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!