You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
12 KiB
263 lines
12 KiB
package alipay
|
|
|
|
import (
|
|
"bkb-payment/pkg/util"
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
baseurl = "https://open-sea-global.alipay.com"
|
|
//privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCuAk8Mon2DT/pMIkItbX9h4+qlzwiFTb4wtB8uPP77x/4Z9rZdtveviFmsgb1DGaNMjGPJ884QB2dY+TclYmaGhZ9ZeICRyLEtptr8atoW1jno+1a60DH9CUEE9wm5Vf+eJ5N+89XDD6eT8WjaQyVWgz1jAJNrpGCSZRSKa6ryGZWMZFx2Rx8k/JEgWJJJyo1OXnlF9G+MQE69/2m8NQx+5GIyAwnT1y0yK9Y0CDAC4kzvuZf7COTYz5ic7MqQ9C1l0mLD2SfJTOzAcSMhAny1GV9j+B7p69ejBk5xHZ7rHOTJLlO2TOOt/zWNt3JvclFfWVQeF5vr+j0CRpcgZ34pAgMBAAECggEAU37qHX7uyQ6cZOHfbVroT7mEg5FnXkeipk4X1CESnRAm/qBie29rREAh/2O1xDfOItIOo/4n94sF7SyQaJDh71S41L68urdZRTWWSJ6hDWo4GXJY+IUkJ23EVDSR5uu8H1CQNs+b1+BwIc4p6OllRjDtSM8i7fjPGhAEnjLxsP8I1hZRL6jdIAqLjQYYVrsxbKwe20ptpiLoPdXlagw4nJ4FHX5eUL3JcnJyYEEO33rQAbCB4v/oq0tTPk5Qy+xq59dxSGHmRVWdl/2lGjkynom4WVwkLl5Pq7+pQvRPQq+Jy28wcde44XVjxuZUofimDui/ROxSQUw5ZoPC+l/+XQKBgQDgPsoVlpTCmCkV7XW2ZZhSTtVt2jC57KeTX+WVzn9Nx1L5LPYZm/a7YwGDdV/rBCe7M4IgMN3WjzSpsAUiZTDeGwpRQQWsZR/Ao3k+IRYm0pgzoj1QhvnWDvULB/0oHzSQ9yKntoiCJQngl87Tky0fentXO1aM5kWB2aoxOrnY6wKBgQDGpmI3x/uGCSlR5X7fRWyW+QKc/UCe3ZmCpTmTEGZ9dnIQCbP8l1mNTGTwBFqyKD2dL2DyueWJfr1OmQK5Th1nb22TWSLdVozE1/t1mot6nAtRt1Jp8VBOuBAVNRAAeMS1Qau148cxGLI1xXJCRA/Ksr0IbH1Z50OaPWaiCheAOwKBgFSOWJUbWqylw5hJGgHU/ULMBx6ND6KL4gRoPKHoY4hoiJj8oy+056xxALkZITn1LyYfngmVY5DsHud9P/JgRbT6bUGGSyVeXEK/YZBT2Y56CnotywD6ZGqa6Ttnn8XpPmELTz3+TisE3Fyb4ZlV/cXI4YlbDp/ClKMJ+GrnwfxRAoGAbbLuJD20gXVHsykX4fY1nD2Qmt8js1dOcZ4KaFMzNe+V15N0KHXwBx570yukZiPguo+yavgLcN1jbycCIRCpHjijey5LGY21GPLosy4P/jpz6cFhqo2POplckEmIN6p5flrwlvZdRpiLuTP6/+sUCWyhBSjcJCyY4XEs3yjRh4cCgYBpBngm/5a+UglZs9TAk67+yPJmcNx4n2Hum7g+JpY6SZuF7cvEPGQfVX4A7kaEGDcs0nQ2ZJRZHNk/HMIm5QYADOK2Tn2sUJIOw1SXQN53wR5/+YRT8YfyOeIBSol5g2Ulc7CLR7atgc9nzgcu4iXFDpPgnwy2FBjdBmuNlu6x8Q=="
|
|
privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCN3rLwTFH+bKixvMNh6NozixMy0ZRg7mCpdfDenGuLvgMSW0Fp6j5ff+0j8JfwVE7Eqo4ztNkNz1KeOqoj4tFeiltmpTsyoKFFOQdHNC3EK8cv8uto+5rVBSj/mZtLYA3exf1Dz+v41jdc6OTCtySSLL9aTfXB6vwpflGVv3PFNp3/w2h3oRvNUg5NIDahMrcEdckV/LbXOV4paULdpvJ02Ghjj36WCTWSHkXIYUsQdidSnGbqnPUtGpvQMM3r4L7xLscAs5e4xkDUhiIcOY8YbywsjD4JbXF5gLlmhPB8l73wJC/z84dTcLGLeJxTalZXBi/2eEGcsWvphqb54P/BAgMBAAECggEAPG9X7sG0VBvZqQ1udfEJstdV8FoTSU+C4e2aFFqx/a+OA23YadQdifUnAh5luz1O6Lx3I1Ow+w8MdNcsz2i6I/nwgcN1elWvHZvzm8OAk4bKrYRgADLefExccLXwz6U1g2b4QsD6FuC6aNvVR5VZAOQLB98aB+egT9S90HrkSGgb4y+KbXe58u0w0385Hsc+bvX/N6tzr8JDixfgIvP//WsUMpzQH3WIE2OPpz+b15IYqo0rTwh0DuiJS+ApGD9KYklvl2Ebtv2PMHi+hmPFyq2+CpokJVMxgJu3jYA22pRRKAmNf1uuW+bGri8Az6o4vWU7ZOZ5JOHtkyztcHrAAQKBgQDrI/BnPYpDp5PzWqwVSPtzUhi3qbEymIfo2vHwbiMVxx/S2dyrnMo4hKi/lLVugDwsuuIZG4YghgW5fxgVDhhVgh0Ln9UDbakrSRNq8eEpaupm38UVUZIicILDzL0QBYHWnnBR2oR3lbBhD1xssJtlgKPgo0+iigOtQiDZW6/FQQKBgQCadJQap4mZdRGIl5mEx+r/fZQoddyt093T44jFFgkpotqy8FXDXUEL+PDK0g6uxwHEMSgoipf3hZHrnHCdNO2ilVhlFXzuHna5wXCiTZdICYNxk8laWXzx32fGwCrVRVabhOGlpGrh+Ee+5c2XsA7sXbquKCK3NqtNKNB6XMYagQKBgDh2e86+p0nRnqRL/JBr4v1xFEBd/g/RMqmGkZwTRld/ZjPiXqvSzXg+2qqOUfbD0i9HfO1cf5ulsxA05ZqAtPUrdkAJVEQre/jJ5mDCzjd81eZ4C0IwQTAF5lCQBEIpoGDh0MTG/RIeHqlf3+i1i8sW1cMmVAQKshFTlMG803tBAoGAMPY5qMVpShshRsJ/6OaS6RC+8aCDJxtdW3jqd0eH+gnk+ApVtYuPPiNY+YJjIyZ0ueO3Tjq4978AxcaesEcB+aMMFWcdZkKD8liOwvSDu1NAtrVZg+mQQQBH3mo2acsELGKQQTkApMdWvv4MEUS/RlBkCCcy8g9DeD8y70cPiYECgYAZrL9dEsw3LkGrLKUDSzD7jaTZ153cCtCJHs+AEKaSEkM2bmdKsutiJnzfua+f+x8KhVoQg3sG6a8/9ujwRm8Vz36SLU4DKN59yyNSDh5W4nJwVI4NiVWoyxCYPw5tTO8ny6N+Wc7/UDa2g08AK9c7DjKMyD7+tlfIe2j7Atqodw=="
|
|
//prefix = "/ams/api"
|
|
prefix = "/ams/sandbox/api"
|
|
//ClientId = "5YBU7N2ZDN8S07987"
|
|
ClientId = "SANDBOX_5YBU7N2ZDN8S07987"
|
|
consult = "/v1/payments/consult"
|
|
pay = "/v1/payments/pay"
|
|
capture = "/v1/payments/capture"
|
|
inquiry = "/v1/payments/inquiryPayment"
|
|
cancel = "/v1/payments/cancel"
|
|
refund = "/v1/payments/refund"
|
|
)
|
|
|
|
type Amount struct {
|
|
Currency string `json:"currency"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
type Env struct {
|
|
OsType string `json:"osType"`
|
|
TerminalType string `json:"terminalType"`
|
|
}
|
|
|
|
type ConsultPay struct {
|
|
ProductCode string `json:"productCode"`
|
|
PaymentAmount Amount `json:"paymentAmount"`
|
|
//UserRegion string `json:"userRegion"`
|
|
//MerchantRegion string `json:"merchantRegion"`
|
|
//SettlementStrategy struct {
|
|
// SettlementCurrency string `json:"settlementCurrency"`
|
|
//} `json:"settlementStrategy"`
|
|
AllowedPaymentMethodRegions []string `json:"allowedPaymentMethodRegions"`
|
|
Env Env `json:"env"`
|
|
PaymentFactor struct {
|
|
PresentmentMode string `json:"presentmentMode"`
|
|
} `json:"paymentFactor"`
|
|
}
|
|
type Logo struct {
|
|
LogoName string `json:"logoName"`
|
|
LogoUrl string `json:"logoUrl"`
|
|
}
|
|
|
|
type ConsultResult struct {
|
|
Result Result `json:"result"`
|
|
PaymentOptions []struct {
|
|
PaymentMethodType string `json:"paymentMethodType"`
|
|
PaymentMethodCategory string `json:"paymentMethodCategory"`
|
|
PaymentMethodRegion []string `json:"paymentMethodRegion"`
|
|
Enabled bool `json:"enabled"`
|
|
DisableReason string `json:"disableReason"`
|
|
Logo Logo `json:"logo"`
|
|
} `json:"paymentOptions"`
|
|
}
|
|
|
|
type PaymentMethod struct {
|
|
PaymentMethodType string `json:"paymentMethodType"`
|
|
PaymentMethodId string `json:"paymentMethodId"`
|
|
}
|
|
|
|
type CreatePay struct {
|
|
Env Env `json:"env"`
|
|
Order struct {
|
|
Merchant struct {
|
|
ReferenceMerchantID string `json:"referenceMerchantId"`
|
|
} `json:"merchant"`
|
|
OrderAmount Amount `json:"orderAmount"`
|
|
OrderDescription string `json:"orderDescription"`
|
|
ReferenceOrderID string `json:"referenceOrderId"`
|
|
} `json:"order"`
|
|
PaymentAmount Amount `json:"paymentAmount"`
|
|
PaymentMethod PaymentMethod `json:"paymentMethod"`
|
|
PaymentNotifyURL string `json:"paymentNotifyUrl"`
|
|
PaymentRedirectURL string `json:"paymentRedirectUrl"`
|
|
PaymentRequestID string `json:"paymentRequestId"` //商家分配的用于标识付款请求的唯一 ID。
|
|
ProductCode string `json:"productCode"` // 固定值
|
|
//SettlementStrategy struct {
|
|
//SettlementCurrency string `json:"settlementCurrency"`
|
|
//} `json:"settlementStrategy"`
|
|
}
|
|
|
|
type InStoreOrder struct {
|
|
Merchant struct {
|
|
ReferenceMerchantID string `json:"referenceMerchantId"`
|
|
MerchantMCC string `json:"merchantMCC"`
|
|
MerchantName string `json:"merchantName"`
|
|
Store struct {
|
|
ReferenceStoreId string `json:"referenceStoreId"`
|
|
StoreName string `json:"storeName"`
|
|
StoreMCC string `json:"storeMCC"`
|
|
} `json:"store"`
|
|
} `json:"merchant"`
|
|
OrderAmount Amount `json:"orderAmount"`
|
|
OrderDescription string `json:"orderDescription"`
|
|
ReferenceOrderID string `json:"referenceOrderId"`
|
|
Env Env `json:"env"`
|
|
PaymentMethod struct {
|
|
PaymentMethodType string `json:"paymentMethodType"`
|
|
PaymentMethodId string `json:"paymentMethodId"`
|
|
} `json:"paymentMethod"`
|
|
}
|
|
|
|
type InStorePay struct {
|
|
ProductCode string `json:"productCode"`
|
|
PaymentRequestID string `json:"paymentRequestId"`
|
|
Order InStoreOrder `json:"order"`
|
|
PaymentAmount Amount `json:"paymentAmount"`
|
|
PaymentMethod PaymentMethod `json:"paymentMethod"`
|
|
PaymentNotifyURL string `json:"paymentNotifyUrl"`
|
|
}
|
|
|
|
type Result struct {
|
|
ResultCode string `json:"resultCode"`
|
|
ResultMessage string `json:"resultMessage"`
|
|
ResultStatus string `json:"resultStatus"`
|
|
}
|
|
|
|
type RedirectActionForm struct {
|
|
Method string `json:"method"`
|
|
Parameters string `json:"parameters"`
|
|
RedirectUrl string `json:"redirectUrl"`
|
|
}
|
|
|
|
type OrderDetail struct {
|
|
Result Result `json:"result"`
|
|
PaymentRequestID string `json:"paymentRequestId"`
|
|
PaymentID string `json:"paymentId"`
|
|
PaymentAmount Amount `json:"paymentAmount"`
|
|
PaymentTime time.Time `json:"paymentTime"`
|
|
PaymentCreateTime string `json:"paymentCreateTime"`
|
|
AppIdentifier string `json:"appIdentifier"`
|
|
NormalURL string `json:"normalUrl"`
|
|
OrderCodeForm struct {
|
|
CodeDetails []struct {
|
|
CodeValue string `json:"codeValue"`
|
|
DisplayType string `json:"displayType"`
|
|
} `json:"codeDetails"`
|
|
ExpireTime string `json:"expireTime"`
|
|
} `json:"orderCodeForm"`
|
|
SchemeURL string `json:"schemeUrl"`
|
|
PaymentStatus string `json:"paymentStatus"`
|
|
RedirectActionForm RedirectActionForm `json:"redirectActionForm"`
|
|
Transactions any `json:"transactions"`
|
|
}
|
|
|
|
type Quote struct {
|
|
QuoteId string `json:"quoteId"`
|
|
QuoteCurrencyPair string `json:"quoteCurrencyPair"`
|
|
QuotePrice float64 `json:"quotePrice"`
|
|
QuoteStartTime time.Time `json:"quoteStartTime"`
|
|
QuoteExpiryTime time.Time `json:"quoteExpiryTime"`
|
|
Guaranteed bool `json:"guaranteed"`
|
|
}
|
|
|
|
type InStoreResult struct {
|
|
Result Result `json:"result"`
|
|
PaymentRequestID string `json:"paymentRequestId"`
|
|
PaymentID string `json:"paymentId"`
|
|
PaymentAmount Amount `json:"paymentAmount"`
|
|
PaymentTime time.Time `json:"paymentTime"`
|
|
PaymentCreateTime string `json:"paymentCreateTime"`
|
|
PspCustomerInfo struct {
|
|
PspName string `json:"pspName"`
|
|
PspCustomerId string `json:"pspCustomerId"`
|
|
DisplayCustomerId string `json:"displayCustomerId"`
|
|
} `json:"pspCustomerInfo"`
|
|
ChallengeActionForm struct {
|
|
ChallengeType string `json:"challengeType"`
|
|
TriggerSource string `json:"triggerSource"`
|
|
ExtendInfo string `json:"extendInfo"`
|
|
} `json:"challengeActionForm"`
|
|
RedirectActionForm RedirectActionForm `json:"redirectActionForm"`
|
|
GrossSettlementAmount Amount `json:"grossSettlementAmount"`
|
|
SettlementQuote Quote `json:"settlementQuote"`
|
|
}
|
|
|
|
type CapturePay struct {
|
|
PaymentID string `json:"paymentId"`
|
|
CaptureRequestID string `json:"captureRequestId"`
|
|
CaptureAmount Amount `json:"captureAmount"`
|
|
}
|
|
|
|
type CaptureDetail struct {
|
|
AcquirerReferenceNo string `json:"acquirerReferenceNo"`
|
|
Result Result `json:"result"`
|
|
CaptureTime string `json:"captureTime"`
|
|
PaymentID string `json:"paymentId"`
|
|
CaptureRequestID string `json:"captureRequestId"`
|
|
CaptureID string `json:"captureId"`
|
|
CaptureAmount Amount `json:"captureAmount"`
|
|
}
|
|
|
|
type NotifyPaymentParams struct {
|
|
NotifyType string `json:"notifyType"`
|
|
}
|
|
|
|
type CancelDetail struct {
|
|
Result Result `json:"result"`
|
|
PaymentRequestID string `json:"paymentRequestId"`
|
|
PaymentID string `json:"paymentId"`
|
|
CancelTime time.Time `json:"cancelTime"`
|
|
}
|
|
|
|
type RefundRequest struct {
|
|
RefundRequestId string `json:"refundRequestId"`
|
|
PaymentId string `json:"paymentId"`
|
|
ReferenceRefundId string `json:"referenceRefundId"`
|
|
RefundAmount Amount `json:"refundAmount"`
|
|
RefundReason string `json:"refundReason"`
|
|
RefundNotifyUrl string `json:"refundNotifyUrl"`
|
|
}
|
|
|
|
type RefundResult struct {
|
|
Result Result `json:"result"`
|
|
RefundRequestId string `json:"refundRequestId"`
|
|
RefundId string `json:"refundId"`
|
|
PaymentId string `json:"paymentId"`
|
|
AcquirerReferenceNo string `json:"acquirerReferenceNo"`
|
|
RefundAmount Amount `json:"refundAmount"`
|
|
RefundTime time.Time `json:"refundTime"`
|
|
GrossSettlementAmount Amount `json:"grossSettlementAmount"`
|
|
SettlementQuote Quote `json:"settlementQuote"`
|
|
}
|
|
|
|
func sign(requestURI, clientId, requestTime, requestBody string) string {
|
|
content := fmt.Sprintf("POST %s\n%s.%s.%s", requestURI, clientId, requestTime, requestBody)
|
|
|
|
block, _ := pem.Decode([]byte(util.FormatPrivateKey(privateKey)))
|
|
|
|
if block == nil {
|
|
panic("failed to parse PEM block containing the key")
|
|
}
|
|
priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
hashed := sha256.Sum256([]byte(content))
|
|
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey.(*rsa.PrivateKey), crypto.SHA256, hashed[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
encodedSignature := base64.StdEncoding.EncodeToString(signature)
|
|
urlEncodedSignature := url.QueryEscape(encodedSignature)
|
|
return urlEncodedSignature
|
|
}
|
|
|