Chuyển đổi phiên bản và thuật toán mã hóa - Cổng thanh toán VNPAY
Thông báo
Để đảm bảo an toàn bảo mật thông tin thanh toán, VNPAY khuyến cáo merchant đã tích hợp Cổng thanh toán VNPAY chuyển đổi phiên bản và thuật toán mã hóa tạo checksum như: MD5,SHA256
các thuật toán mã hóa phiên bản cũ đã kém an toàn và bảo mật. Merchant cần chuyển đổi sang phiên bản Version 2.1.0 và thuật toán mã hóa HMACSHA512
Tạo URL Thanh toán
URL thanh toán (Sandbox): https://sandbox.vnpayment.vn/paymentv2/vpcpay.html
Phương thức: GET
URL thanh toán chuyển hướng mà hệ thống merchant tạo đầy đủ có dạng:
https://sandbox.vnpayment.vn/paymentv2/vpcpay.html?vnp_Amount=1806000&vnp_Command=pay&vnp_CreateDate=20210801153333&vnp_CurrCode=VND&vnp_IpAddr=127.0.0.1&vnp_Locale=vn&vnp_OrderInfo=Thanh+toan+don+hang+%3A5&vnp_OrderType=other&vnp_ReturnUrl=https%3A%2F%2Fdomainmerchant.vn%2FReturnUrl&vnp_TmnCode=DEMOV210&vnp_TxnRef=5&vnp_Version=2.1.0&vnp_SecureHash=3e0d61a0c0534b2e36680b3f7277743e8784cc4e1d68fa7d276e79c23be7d6318d338b477910a27992f5057bb1582bd44bd82ae8009ffaf6d141219218625c42
Danh sách tham số - Thông tin gửi sang VNPAY (vnp_Command=pay)
Lưu ý
Danh sách tham số gửi sang Cổng thanh toán VNPAY với phiên bản 2.1.0 có thay đổi so với phiên bản 2.0.0 và 2.0.1 là vnp_SecureHashType
vnp_SecureHashType
: Phiên bản 2.0.0, 2.0.1 bắt buộc gửi sang.
vnp_SecureHashType
: Phiên bản 2.1.0 không gửi sang VNPAY.
Tham số
Kiểu dữ liệu
Bắt buộc/Tùy chọn
Mô tả
vnp_Version
Alphanumeric[1,8]
Bắt buộc
Phiên bản api mà merchant kết nối. Phiên bản hiện tại là : 2.1.0
vnp_Command
Alpha[1,16]
Bắt buộc
Mã API sử dụng, mã cho giao dịch thanh toán là: pay
vnp_TmnCode
Alphanumeric[8]
Bắt buộc
Mã website của merchant trên hệ thống của VNPAY. Ví dụ: 2QXUI4J4
vnp_Amount
Numeric[1,12]
Bắt buộc
Số tiền thanh toán. Số tiền không mang các ký tự phân tách thập phân, phần nghìn, ký tự tiền tệ. Để gửi số tiền thanh toán là 10,000 VND (mười nghìn VNĐ) thì merchant cần nhân thêm 100 lần (khử phần thập phân), sau đó gửi sang VNPAY là: 1000000
vnp_BankCode
Alphanumeric[3,20]
Tùy chọn
Mã phương thức thanh toán, mã loại ngân hàng hoặc ví điện tử thanh toán.
Nếu không gửi sang tham số này, chuyển hướng người dùng sang VNPAY chọn phương thức thanh toán.
Lưu ý:
Các mã loại hình thức thanh toán lựa chọn tại website-ứng dụng của merchant
vnp_BankCode=VNPAYQR
Thanh toán quét mã QR
vnp_BankCode=VNBANK
Thẻ ATM - Tài khoản ngân hàng nội địa
vnp_BankCode=INTCARD
Thẻ thanh toán quốc tế
vnp_CreateDate
Numeric[14]
Bắt buộc
Ví dụ: 20170829103111
vnp_CurrCode
Alpha[3]
Bắt buộc
Đơn vị tiền tệ sử dụng thanh toán. Hiện tại chỉ hỗ trợ VND
vnp_IpAddr
Alphanumeric[7,45]
Bắt buộc
Địa chỉ IP của khách hàng thực hiện giao dịch. Ví dụ: 13.160.92.202
vnp_Locale
Alpha[2,5]
Bắt buộc
Ngôn ngữ giao diện hiển thị. Hiện tại hỗ trợ Tiếng Việt (vn), Tiếng Anh (en)
vnp_OrderInfo
Alphanumeric[1,255]
Bắt buộc
Thông tin mô tả nội dung thanh toán (Tiếng Việt, không dấu). Ví dụ: **Nap tien cho thue bao 0123456789. So tien 100,000 VND**
vnp_OrderType
Alpha[1,100]
Bắt buộc
Mã danh mục hàng hóa. Mỗi hàng hóa sẽ thuộc một nhóm danh mục do VNPAY quy định. Xem thêm bảng Danh mục hàng hóa
vnp_ReturnUrl
Alphanumeric[10,255]
Bắt buộc
URL thông báo kết quả giao dịch khi Khách hàng kết thúc thanh toán. Ví dụ: https://domain.vn/VnPayReturn
vnp_ExpireDate
Numeric[14]
Bắt buộc
Thời gian hết hạn thanh toán GMT+7, định dạng: yyyyMMddHHmmss
vnp_TxnRef
Alphanumeric[1,100]
Bắt buộc
Mã tham chiếu của giao dịch tại hệ thống của merchant. Mã này là duy nhất dùng để phân biệt các đơn hàng gửi sang VNPAY. Không được trùng lặp trong ngày. Ví dụ: 23554
vnp_SecureHash
Alphanumeric[32,256]
Bắt buộc
Mã kiểm tra (checksum) để đảm bảo dữ liệu của giao dịch không bị thay đổi trong quá trình chuyển từ merchant sang VNPAY. Việc tạo ra mã này phụ thuộc vào cấu hình của merchant và phiên bản api sử dụng. Phiên bản hiện tại hỗ trợ SHA256, HMACSHA512.
Lưu ý
Dữ liệu checksum được thành lập dựa trên việc sắp xếp tăng dần của tên tham số (QueryString)
Số tiền cần thanh toán nhân với 100 để triệt tiêu phần thập phân trước khi gửi sang VNPAY
vnp_BankCode
: Giá trị này tùy chọn.
- Nếu loại bỏ tham số không gửi sang, khách hàng sẽ chọn phương thức thanh toán, ngân hàng thanh toán tại VNPAY.
- Nếu thiết lập giá trị (chọn Ngân hàng thanh toán tại Website-ứng dụng TMĐT), Tham khảo bảng mã trả về tại API:
Endpoint:
https://sandbox.vnpayment.vn/qrpayauth/api/merchant/get_bank_list
Http method:
POST
Content-Type:
application/x-www-form-urlencoded
key
tmn_code
value
Theo mã định danh kết nối (vnp_TmnCode) VNPAY cung cấp
Trong URL thanh toán có tham số vnp_ReturnUrl
là URL thông báo kết quả giao dịch khi Khách hàng kết thúc thanh toán
Code cài đặt
<?php
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
date_default_timezone_set('Asia/Ho_Chi_Minh');
$vnp_Url = "https://sandbox.vnpayment.vn/paymentv2/vpcpay.html" ;
$vnp_Returnurl = "https://localhost/vnpay_php/vnpay_return.php" ;
$vnp_TmnCode = "" ; //Mã website tại VNPAY
$vnp_HashSecret = "" ; //Chuỗi bí mật
$vnp_TxnRef = $_POST['order_id']; //Mã đơn hàng. Trong thực tế Merchant cần insert đơn hàng vào DB và gửi mã này
sang VNPAY
$vnp_OrderInfo = $_POST['order_desc'];
$vnp_OrderType = $_POST['order_type'];
$vnp_Amount = $_POST['amount'] * 100;
$vnp_Locale = $_POST['language'];
$vnp_BankCode = $_POST['bank_code'];
$vnp_IpAddr = $_SERVER['REMOTE_ADDR'];
//Add Params
$inputData = array(
"vnp_Version" => "2.1.0", //Phiên bản cũ là 2.0.0, 2.0.1 thay đổi sang 2.1.0
"vnp_TmnCode" => $vnp_TmnCode,
"vnp_Amount" => $vnp_Amount,
"vnp_Command" => "pay",
"vnp_CreateDate" => date('YmdHis'),
"vnp_CurrCode" => "VND",
"vnp_IpAddr" => $vnp_IpAddr,
"vnp_Locale" => $vnp_Locale,
"vnp_OrderInfo" => $vnp_OrderInfo,
"vnp_OrderType" => $vnp_OrderType,
"vnp_ReturnUrl" => $vnp_Returnurl,
"vnp_TxnRef" => $vnp_TxnRef
);
if (isset($vnp_BankCode) && $vnp_BankCode != "") {
$inputData['vnp_BankCode'] = $vnp_BankCode;
}
//var_dump($inputData);
ksort($inputData);
$query = "";
$i = 0;
$hashdata = "";
//Build querystring phiên bản cũ 2.0.0, 2.0.1
foreach ($inputData as $key => $value) {
if ($i == 1) {
$hashdata .= '&' . $key . "=" . $value;
} else {
$hashdata .= $key . "=" . $value;
$i = 1;
}
$query .= urlencode($key) . "=" . urlencode($value) . '&';
}
Chuyển thành:
//Build querystring phiên bản mới 2.1.0
foreach ($inputData as $key => $value) {
if ($i == 1) {
$hashdata .= '&' . urlencode($key) . "=" . urlencode($value);
} else {
$hashdata .= urlencode($key) . "=" . urlencode($value);
$i = 1;
}
$query .= urlencode($key) . "=" . urlencode($value) . '&';
}
$vnp_Url = $vnp_Url . "?" . $query;
if (isset($vnp_HashSecret)) {
//Tạo vnp_SecureHash và tạo URL chuyển hướng phiên bản cũ 2.0.0, 2.0.1
$vnpSecureHash = md5($vnp_HashSecret . $hashdata);
$vnp_Url .= 'vnp_SecureHashType=MD5&vnp_SecureHash=' . $vnpSecureHash;
hoặc
$vnpSecureHash = hash('sha256', $vnp_HashSecret . $hashdata);
$vnp_Url .= 'vnp_SecureHashType=SHA256&vnp_SecureHash=' . $vnpSecureHash;
Chuyển thành:
//Tạo vnp_SecureHash và tạo URL chuyển hướng phiên bản mới 2.1.0
$vnpSecureHash = hash_hmac('sha512', $hashdata, $vnp_HashSecret);//
$vnp_Url .= 'vnp_SecureHash=' . $vnpSecureHash;
}
if (isset($_POST['redirect'])) {
header('Location: ' . $vnp_Url);
die();
}
// vui lòng tham khảo thêm tại code demo
private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
txtOrderDesc.Text = "Nhap noi dung thanh toan";
txtExpire.Text = DateTime.Now.AddMinutes(15).ToString("yyyyMMddHHmmss");
}
}
protected void btnPay_Click(object sender, EventArgs e)
{
//Get Config Info
string vnp_Returnurl = ConfigurationManager.AppSettings["vnp_Returnurl"]; //URL nhan ket qua tra ve
string vnp_Url = ConfigurationManager.AppSettings["vnp_Url"]; //URL thanh toan cua VNPAY
string vnp_TmnCode = ConfigurationManager.AppSettings["vnp_TmnCode"]; //Ma website
string vnp_HashSecret = ConfigurationManager.AppSettings["vnp_HashSecret"]; //Chuoi bi mat
if (string.IsNullOrEmpty(vnp_TmnCode) || string.IsNullOrEmpty(vnp_HashSecret))
{
lblMessage.Text = "Vui lòng cấu hình các tham số: vnp_TmnCode,vnp_HashSecret trong file web.config";
return;
}
//Get payment input
OrderInfo order = new OrderInfo();
//Save order to db
order.OrderId = DateTime.Now.Ticks; // Giả lập mã giao dịch hệ thống merchant gửi sang VNPAY
order.Amount = 100000; // Giả lập số tiền thanh toán hệ thống merchant gửi sang VNPAY 100,000 VND
order.Status = "0"; //0: Trạng thái thanh toán "chờ thanh toán" hoặc "Pending".
order.OrderDesc = txtOrderDesc.Text;
order.CreatedDate = DateTime.Now;
string locale = cboLanguage.SelectedItem.Value;
//Build URL for VNPAY
Đơn vị cập nhật lại thư viện VnPayLibrar.cs. Trong thư viện này VNPAY đã thay đổi thuật toán mã hóa MD5 hoặc SHA256
sang HMACSHA512
Tải "VnPayLibrary.cs" về tại đây
VnPayLibrary vnpay = new VnPayLibrary();
vnpay.AddRequestData("vnp_Version", "2.1.0"); //Phiên bản cũ là 2.0.0, 2.0.1 thay đổi sang 2.1.0
vnpay.AddRequestData("vnp_Command", "pay");
vnpay.AddRequestData("vnp_TmnCode", vnp_TmnCode);
vnpay.AddRequestData("vnp_Amount", (order.Amount * 100).ToString()); //Số tiền thanh toán. Số tiền không
mang các ký tự phân tách thập phân, phần nghìn, ký tự tiền tệ. Để gửi số tiền thanh toán là 100,000 VND
(một trăm nghìn VNĐ) thì merchant cần nhân thêm 100 lần (khử phần thập phân), sau đó gửi sang VNPAY
là: 10000000
if (cboBankCode.SelectedItem != null && !string.IsNullOrEmpty(cboBankCode.SelectedItem.Value))
{
vnpay.AddRequestData("vnp_BankCode", cboBankCode.SelectedItem.Value);
}
vnpay.AddRequestData("vnp_CreateDate", order.CreatedDate.ToString("yyyyMMddHHmmss"));
vnpay.AddRequestData("vnp_CurrCode", "VND");
vnpay.AddRequestData("vnp_IpAddr", Utils.GetIpAddress());
if (!string.IsNullOrEmpty(locale))
{
vnpay.AddRequestData("vnp_Locale", locale);
}
else
{
vnpay.AddRequestData("vnp_Locale", "vn");
}
vnpay.AddRequestData("vnp_OrderInfo", "Thanh toan don hang:" + order.OrderId);
vnpay.AddRequestData("vnp_OrderType", orderCategory.SelectedItem.Value); //default value: other
vnpay.AddRequestData("vnp_ReturnUrl", vnp_Returnurl);
vnpay.AddRequestData("vnp_TxnRef", order.OrderId.ToString()); // Mã tham chiếu của giao dịch tại hệ
thống của merchant. Mã này là duy nhất dùng để phân biệt các đơn hàng gửi sang VNPAY. Không được
trùng lặp trong ngày
string paymentUrl = vnpay.CreateRequestUrl(vnp_Url, vnp_HashSecret);
log.InfoFormat("VNPAY URL: {0}", paymentUrl);
Response.Redirect(paymentUrl);
}
// vui lòng tham khảo thêm tại code demo
def payment(request):
if request.method == 'POST':
# Process input data and build url payment
form = PaymentForm(request.POST)
if form.is_valid():
order_type = form.cleaned_data['order_type']
order_id = form.cleaned_data['order_id']
amount = form.cleaned_data['amount']
order_desc = form.cleaned_data['order_desc']
bank_code = form.cleaned_data['bank_code']
language = form.cleaned_data['language']
ipaddr = get_client_ip(request)
# Build URL Payment
Đơn vị cập nhật lại thư viện "vnpay.py". Trong thư viện này VNPAY đã thay đổi thuật toán mã hóa MD5 hoặc SHA256
sang HMACSHA512
Tải "vnpay.py" về tại đây
vnp = vnpay()
vnp.requestData['vnp_Version'] = '2.1.0' //Phiên bản cũ là 2.0.0, 2.0.1 thay đổi sang 2.1.0
vnp.requestData['vnp_Command'] = 'pay'
vnp.requestData['vnp_TmnCode'] = settings.VNPAY_TMN_CODE
vnp.requestData['vnp_Amount'] = amount * 100
vnp.requestData['vnp_CurrCode'] = 'VND'
vnp.requestData['vnp_TxnRef'] = order_id
vnp.requestData['vnp_OrderInfo'] = order_desc
vnp.requestData['vnp_OrderType'] = order_type
# Check language, default: vn
if language and language != '':
vnp.requestData['vnp_Locale'] = language
else:
vnp.requestData['vnp_Locale'] = 'vn'
# Check bank_code, if bank_code is empty, customer will be selected bank on VNPAY
if bank_code and bank_code != "":
vnp.requestData['vnp_BankCode'] = bank_code
vnp.requestData['vnp_CreateDate'] = datetime.now().strftime('%Y%m%d%H%M%S')
vnp.requestData['vnp_IpAddr'] = ipaddr
vnp.requestData['vnp_ReturnUrl'] = settings.VNPAY_RETURN_URL
vnpay_payment_url = vnp.get_payment_url(settings.VNPAY_PAYMENT_URL, settings.VNPAY_HASH_SECRET_KEY)
print(vnpay_payment_url)
# Redirect to VNPAY
return redirect(vnpay_payment_url)
else:
print("Form input not validate")
else:
return render(request, "payment.html", {"title": "Thanh toán"})
// vui lòng tham khảo thêm tại code demo
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String vnp_Version = "2.1.0";
String vnp_Command = "pay";
String vnp_OrderInfo = req.getParameter("vnp_OrderInfo");
String orderType = req.getParameter("ordertype");
String vnp_TxnRef = Config.getRandomNumber(8);
String vnp_IpAddr = Config.getIpAddress(req);
String vnp_TmnCode = Config.vnp_TmnCode;
int amount = Integer.parseInt(req.getParameter("amount")) * 100;
Map vnp_Params = new HashMap<>();
vnp_Params.put("vnp_Version", vnp_Version); //Phiên bản cũ là 2.0.0, 2.0.1 thay đổi sang 2.1.0
vnp_Params.put("vnp_Command", vnp_Command);
vnp_Params.put("vnp_TmnCode", vnp_TmnCode);
vnp_Params.put("vnp_Amount", String.valueOf(amount));
vnp_Params.put("vnp_CurrCode", "VND");
String bank_code = req.getParameter("bankcode");
if (bank_code != null && !bank_code.isEmpty()) {
vnp_Params.put("vnp_BankCode", bank_code);
}
vnp_Params.put("vnp_TxnRef", vnp_TxnRef);
vnp_Params.put("vnp_OrderInfo", vnp_OrderInfo);
vnp_Params.put("vnp_OrderType", orderType);
String locate = req.getParameter("language");
if (locate != null && !locate.isEmpty()) {
vnp_Params.put("vnp_Locale", locate);
} else {
vnp_Params.put("vnp_Locale", "vn");
}
vnp_Params.put("vnp_ReturnUrl", Config.vnp_Returnurl);
vnp_Params.put("vnp_IpAddr", vnp_IpAddr);
Calendar cld = Calendar.getInstance(TimeZone.getTimeZone("Etc/GMT+7"));
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
String vnp_CreateDate = formatter.format(cld.getTime());
vnp_Params.put("vnp_CreateDate", vnp_CreateDate);
//Build data to hash and querystring
List fieldNames = new ArrayList(vnp_Params.keySet());
Collections.sort(fieldNames);
StringBuilder hashData = new StringBuilder();
StringBuilder query = new StringBuilder();
Iterator itr = fieldNames.iterator();
//Build data với phiên bản cũ 2.0.0, 2.0.1
while (itr.hasNext()) {
String fieldName = (String) itr.next();
String fieldValue = (String) vnp_Params.get(fieldName);
if ((fieldValue != null) && (fieldValue.length() > 0)) {
//Build hash data
hashData.append(fieldName);
hashData.append('=');
hashData.append(fieldValue);
//Build query
query.append(URLEncoder.encode(fieldName, StandardCharsets.US_ASCII.toString()));
query.append('=');
query.append(URLEncoder.encode(fieldValue, StandardCharsets.US_ASCII.toString()));
if (itr.hasNext()) {
query.append('&');
hashData.append('&');
}
}
}
Chuyển thành:
//Build data với phiên bản mới 2.1.0:
while (itr.hasNext()) {
String fieldName = (String) itr.next();
String fieldValue = (String) vnp_Params.get(fieldName);
if ((fieldValue != null) && (fieldValue.length() > 0)) {
//Build hash data
hashData.append(fieldName);
hashData.append('=');
hashData.append(URLEncoder.encode(fieldValue, StandardCharsets.US_ASCII.toString()));
//Build query
query.append(URLEncoder.encode(fieldName, StandardCharsets.US_ASCII.toString()));
query.append('=');
query.append(URLEncoder.encode(fieldValue, StandardCharsets.US_ASCII.toString()));
if (itr.hasNext()) {
query.append('&');
hashData.append('&');
}
}
}
String queryUrl = query.toString();
//Tạo vnp_SecureHash và tạo URL chuyển hướng phiên bản cũ 2.0.0, 2.0.1
String vnp_SecureHash = Config.md5(Config.vnp_HashSecret + hashData.toString());
queryUrl += "&vnp_SecureHashType=MD5&vnp_SecureHash=" + vnp_SecureHash;
Hoăc
String vnp_SecureHash = Config.Sha256(Config.vnp_HashSecret + hashData.toString());
queryUrl += "&vnp_SecureHashType=SHA256&vnp_SecureHash=" + vnp_SecureHash;
Chuyển thành:
//Tạo vnp_SecureHash và tạo URL chuyển hướng phiên bản mới 2.1.0
String vnp_SecureHash = Config.hmacSHA512(Config.vnp_HashSecret, hashData.toString());
queryUrl += "&vnp_SecureHash=" + vnp_SecureHash;
//Trong đó với Config.hmacSHA512:
public static String hmacSHA512(final String key, final String data) {
try {
if (key == null || data == null) {
throw new NullPointerException();
}
final Mac hmac512 = Mac.getInstance("HmacSHA512");
byte[] hmacKeyBytes = key.getBytes();
final SecretKeySpec secretKey = new SecretKeySpec(hmacKeyBytes, "HmacSHA512");
hmac512.init(secretKey);
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
byte[] result = hmac512.doFinal(dataBytes);
StringBuilder sb = new StringBuilder(2 * result.length);
for (byte b : result) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
} catch (Exception ex) {
return "";
}
}
String paymentUrl = Config.vnp_PayUrl + "?" + queryUrl;
com.google.gson.JsonObject job = new JsonObject();
job.addProperty("code", "00");
job.addProperty("message", "success");
job.addProperty("data", paymentUrl);
Gson gson = new Gson();
resp.getWriter().write(gson.toJson(job));
}
//vui lòng tham khảo thêm tại code demo
router.post('/create_payment_url', function (req, res, next) {
var ipAddr = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
var config = require('config');
var dateFormat = require('dateformat');
var tmnCode = config.get('vnp_TmnCode');
var secretKey = config.get('vnp_HashSecret');
var vnpUrl = config.get('vnp_Url');
var returnUrl = config.get('vnp_ReturnUrl');
var date = new Date();
var createDate = dateFormat(date, 'yyyymmddHHmmss');
var orderId = dateFormat(date, 'HHmmss');
var amount = req.body.amount;
var bankCode = req.body.bankCode;
var orderInfo = req.body.orderDescription;
var orderType = req.body.orderType;
var locale = req.body.language;
if(locale === null || locale === ''){
locale = 'vn';
}
var currCode = 'VND';
var vnp_Params = {};
vnp_Params['vnp_Version'] = '2.1.0';
vnp_Params['vnp_Command'] = 'pay';
vnp_Params['vnp_TmnCode'] = tmnCode;
// vnp_Params['vnp_Merchant'] = ''
vnp_Params['vnp_Locale'] = locale;
vnp_Params['vnp_CurrCode'] = currCode;
vnp_Params['vnp_TxnRef'] = orderId;
vnp_Params['vnp_OrderInfo'] = orderInfo;
vnp_Params['vnp_OrderType'] = orderType;
vnp_Params['vnp_Amount'] = amount * 100;
vnp_Params['vnp_ReturnUrl'] = returnUrl;
vnp_Params['vnp_IpAddr'] = ipAddr;
vnp_Params['vnp_CreateDate'] = createDate;
if(bankCode !== null && bankCode !== ''){
vnp_Params['vnp_BankCode'] = bankCode;
}
Trong đó sortObject:
function sortObject(obj) {
var sorted = {};
var str = [];
var key;
for (key in obj){
if (obj.hasOwnProperty(key)) {
str.push(encodeURIComponent(key));
}
}
str.sort();
for (key = 0; key < str.length; key++) {
sorted[str[key]] = encodeURIComponent(obj[str[key]]).replace(/%20/g, "+");
}
return sorted;
}
vnp_Params = sortObject(vnp_Params);
//Build Hash data và querystring với phiên bản cũ 2.0.0, 2.0.1:
var querystring = require('qs');
var signData = secretKey + querystring.stringify(vnp_Params, { encode: false });
var md5 = require('md5');
var secureHash = md5(signData);
vnp_Params['vnp_SecureHashType'] = 'MD5';
vnp_Params['vnp_SecureHash'] = secureHash;
vnpUrl += '?' + querystring.stringify(vnp_Params, { encode: true });
res.redirect(vnpUrl)
Chuyển thành:
//Build Hash data và querystring với phiên bản mới 2.1.0:
var querystring = require('qs');
var signData = querystring.stringify(vnp_Params, { encode: false });
var crypto = require("crypto");
var hmac = crypto.createHmac("sha512", secretKey);
var signed = hmac.update(new Buffer(signData, 'utf-8')).digest("hex");
vnp_Params['vnp_SecureHash'] = signed;
vnpUrl += '?' + querystring.stringify(vnp_Params, { encode: false });
res.redirect(vnpUrl)
});
// Vui lòng tham khảo thêm tại code demo
Cài đặt Code IPN URL
- Phương thức: GET
Đây là địa chỉ để hệ thống merchant nhận kết quả thanh toán trả về từ VNPAY.
Trên URL VNPAY gọi về có mang thông tin thanh toán để căn cứ vào kết quả đó Website TMĐT xử lý các bước tiếp theo (ví dụ: cập nhật kết quả thanh toán vào Database …)
VNPAY trả về kết quả thanh toán URL có dạng:
https://{domain}/IPN?vnp_Amount=1000000& vnp_BankCode=NCB& vnp_BankTranNo=20170829152730& vnp_CardType=ATM& vnp_OrderInfo=Thanh+toan+don+hang+thoi+gian%3A+2017-08-29+15%3A27%3A02& vnp_PayDate=20170829153052& vnp_ResponseCode=00& vnp_TmnCode=2QXUI4J4& vnp_TransactionNo=12996460& vnp_TxnRef=23597& vnp_SecureHashType=SHA256& vnp_SecureHash=20081f0ee1cc6b524e273b6d4050fefd
Danh sách tham số - Thông tin nhận về từ VNPAY (vnp_Command=pay)
Danh sách tham số gửi sang Cổng thanh toán VNPAY với phiên bản 2.1.0 có thay đổi so với phiên bản 2.0.0 vnp_TransactionStatus
vnp_TransactionStatus
: Phiên bản 2.0.0 không trả về tham số này.
vnp_TransactionStatus
: Phiên bản 2.1.0 trả về thêm tham số này.
Tham số
Kiểu dữ liệu
Bắt buộc/Tùy chọn
Mô tả
vnp_TmnCode
Alphanumeric[8]
Bắt buộc
Mã website của merchant trên hệ thống của VNPAY. Ví dụ: 2QXUI4J4
vnp_Amount
Numeric[1,12]
Bắt buộc
Số tiền thanh toán. VNPAY phản hồi số tiền nhân thêm 100 lần.
vnp_BankCode
Alphanumeric[3,20]
Bắt buộc
Mã Ngân hàng thanh toán. Ví dụ: NCB
vnp_BankTranNo
Alphanumeric[1,255]
Tùy chọn
Mã giao dịch tại Ngân hàng. Ví dụ: NCB20170829152730
vnp_CardType
Alpha[2,20]
Tùy chọn
Loại tài khoản/thẻ khách hàng sử dụng:ATM,QRCODE
vnp_PayDate
Numeric[14]
Tùy chọn
Thời gian thanh toán. Định dạng: yyyyMMddHHmmss
vnp_OrderInfo
Alphanumeric[1,255]
Bắt buộc
Thông tin mô tả nội dung thanh toán (Tiếng Việt, không dấu). Ví dụ: **Nap tien cho thue bao 0123456789. So tien 100,000 VND**
vnp_TransactionNo
Numeric[1,15]
Bắt buộc
Mã giao dịch ghi nhận tại hệ thống VNPAY. Ví dụ: 20170829153052
vnp_ResponseCode
Numeric[2]
Bắt buộc
Mã phản hồi kết quả thanh toán. Quy định mã trả lời 00 ứng với kết quả Thành công cho tất cả các API. Tham khảo thêm tại bảng mã lỗi
vnp_TransactionStatus
Numeric[2]
Bắt buộc
Mã phản hồi kết quả thanh toán. Tình trạng của giao dịch tại Cổng thanh toán VNPAY.
-00: Giao dịch thanh toán được thực hiện thành công tại VNPAY
-Khác 00: Giao dịch không thành công tại VNPAY
Tham khảo thêm tại bảng mã lỗi
vnp_TxnRef
Alphanumeric[1,100]
Bắt buộc
Giống mã gửi sang VNPAY khi gửi yêu cầu thanh toán. Ví dụ: 23554
vnp_SecureHashType
Alphanumeric[3,10]
Tùy chọn
Loại mã băm sử dụng: SHA256, HmacSHA512
vnp_SecureHash
Alphanumeric[32,256]
Bắt buộc
Mã kiểm tra (checksum) để đảm bảo dữ liệu của giao dịch không bị thay đổi trong quá trình chuyển từ VNPAY về Website TMĐT.
Cần kiểm tra đúng checksum khi bắt đầu xử lý yêu cầu (trước khi thực hiện các yêu cầu khác)
Lưu ý
Merchant/website TMĐT thực hiện kiểm tra sự toàn vẹn của dữ liệu (checksum) trước khi thực hiện các thao tác khác
Thao tác cập nhật/xử lý kết quả sau khi thanh toán được thực hiện tại URL này
Đây là URL server - call - server (Máy chủ VNPAY gọi máy chủ Merchant/website TMĐT)
Merchant trả dữ liệu lại cho VNPAY bằng mã RspCode và Message định dạng JSON:
Trong đó:
RspCode là mã lỗi tình trạng cập nhật trạng thái thanh toán của giao dịch tại đầu IPN của merchant.
Message là mô tả mã lỗi của RspCode
Merchant cần tuân thủ theo các trường hợp kiểm và phản hồi lại RspCode cho VNPAY. Vui lòng tham khảo thêm tại code demo IPN của VNPAY
Cơ chế retry IPN:
Hệ thống VNPAY căn cứ theo RspCode phản hồi từ merchant để kết thúc luồng hay bật cơ chế retry
RspCode: 00, 02 là mã lỗi IPN của merchant phản hồi đã cập nhật được tình trạng giao dịch. VNPAY kết thúc luồng
RspCode: 01, 04, 97, 99 hoặc IPN timeout là mã lỗi IPN merchant không cập nhật được tình trạng giao dịch. VNPAY bật cơ chế retry IPN
Tổng số lần gọi tối đa: 10 lần
Khoảng cách giữa các lần gọi lại: 5 phút
Code cài đặt
/* Payment Notify
* IPN URL: Ghi nhận kết quả thanh toán từ VNPAY
* Các bước thực hiện:
* Kiểm tra checksum
* Tìm giao dịch trong database
* Kiểm tra số tiền giữa hai hệ thống
* Kiểm tra tình trạng của giao dịch trước khi cập nhật
* Cập nhật kết quả vào Database
* Trả kết quả ghi nhận lại cho VNPAY
*/
require_once("./config.php");
$inputData = array();
$returnData = array();
foreach ($_GET as $key => $value) {
if (substr($key, 0, 4) == "vnp_") {
$inputData[$key] = $value;
}
}
$vnp_SecureHash = $inputData['vnp_SecureHash'];
unset($inputData['vnp_SecureHash']);
ksort($inputData);
$i = 0;
$hashData = "";
//Build querystring phiên bản cũ 2.0.0, 2.0.1
foreach ($inputData as $key => $value) {
if ($i == 1) {
$hashdata .= '&' . $key . "=" . $value;
} else {
$hashdata .= $key . "=" . $value;
$i = 1;
}
}
Chuyển thành:
//Build querystring phiên bản mới 2.1.0
foreach ($inputData as $key => $value) {
if ($i == 1) {
$hashData = $hashData . '&' . urlencode($key) . "=" . urlencode($value);
} else {
$hashData = $hashData . urlencode($key) . "=" . urlencode($value);
$i = 1;
}
}
//Tạo secureHash phiên bản cũ 2.0.0, 2.0.1
$secureHash = md5($vnp_HashSecret . $hashdata);
hoặc
$secureHash = hash('sha256', $vnp_HashSecret . $hashdata);
Chuyển thành:
//Tạo secureHash phiên bản mới 2.1.0
$secureHash = hash_hmac('sha512', $hashData, $vnp_HashSecret);
$vnpTranId = $inputData['vnp_TransactionNo']; //Mã giao dịch tại VNPAY
$vnp_BankCode = $inputData['vnp_BankCode']; //Ngân hàng thanh toán
$vnp_Amount = $inputData['vnp_Amount']/100; // Số tiền thanh toán VNPAY phản hồi
$Status = 0; // Là trạng thái thanh toán của giao dịch chưa có IPN lưu tại hệ thống của merchant chiều khởi tạo
URL thanh toán.
$orderId = $inputData['vnp_TxnRef'];
try {
//Check Orderid
//Kiểm tra checksum của dữ liệu
if ($secureHash == $vnp_SecureHash) {
//Lấy thông tin đơn hàng lưu trong Database và kiểm tra trạng thái của đơn hàng, mã đơn hàng là: $orderId
//Việc kiểm tra trạng thái của đơn hàng giúp hệ thống không xử lý trùng lặp, xử lý nhiều lần một giao dịch
//Giả sử: $order = mysqli_fetch_assoc($result);
$order = NULL;
if ($order != NULL) {
if($order["Amount"] == $vnp_Amount) //Kiểm tra số tiền thanh toán của giao dịch: giả sử số tiền
kiểm tra là đúng. //$order["Amount"] == $vnp_Amount
{
if ($order["Status"] != NULL && $order["Status"] == 0) {
if ($inputData['vnp_ResponseCode'] == '00' && $inputData['vnp_TransactionStatus'] == '00') {
$Status = 1; // Trạng thái thanh toán thành công
} else {
$Status = 2; // Trạng thái thanh toán thất bại / lỗi
}
//Cài đặt Code cập nhật kết quả thanh toán, tình trạng đơn hàng vào DB
//
//
//
//Trả kết quả về cho VNPAY: Website/APP TMĐT ghi nhận yêu cầu thành công
$returnData['RspCode'] = '00';
$returnData['Message'] = 'Confirm Success';
} else {
$returnData['RspCode'] = '02';
$returnData['Message'] = 'Order already confirmed';
}
}
else {
$returnData['RspCode'] = '04';
$returnData['Message'] = 'invalid amount';
}
} else {
$returnData['RspCode'] = '01';
$returnData['Message'] = 'Order not found';
}
} else {
$returnData['RspCode'] = '97';
$returnData['Message'] = 'Invalid signature';
}
} catch (Exception $e) {
$returnData['RspCode'] = '99';
$returnData['Message'] = 'Unknow error';
}
//Trả lại VNPAY theo định dạng JSON
echo json_encode($returnData);
private static readonly ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected void Page_Load(object sender, EventArgs e)
{
string returnContent = string.Empty;
if (Request.QueryString.Count > 0)
{
string vnp_HashSecret = ConfigurationManager.AppSettings["vnp_HashSecret"]; //Secret key
var vnpayData = Request.QueryString;
Đơn vị cập nhật lại thư viện VnPayLibrar.cs. Trong thư viện này VNPAY đã thay đổi thuật toán mã hóa MD5 hoặc SHA256
sang HMACSHA512
Tải "VnPayLibrary.cs" về tại đây
VnPayLibrary vnpay = new VnPayLibrary();
foreach (string s in vnpayData)
{
//get all querystring data
if (!string.IsNullOrEmpty(s) && s.StartsWith("vnp_"))
{
vnpay.AddResponseData(s, vnpayData[s]);
}
}
//Lay danh sach tham so tra ve tu VNPAY
//vnp_TxnRef: Ma don hang merchant gui VNPAY tai command=pay
//vnp_TransactionNo: Ma GD tai he thong VNPAY
//vnp_ResponseCode:Response code from VNPAY: 00: Thanh cong, Khac 00: Xem tai lieu
//vnp_SecureHash: HmacSHA512 cua du lieu tra ve
long orderId = Convert.ToInt64(vnpay.GetResponseData("vnp_TxnRef"));
long vnp_Amount = Convert.ToInt64(vnpay.GetResponseData("vnp_Amount"))/100;
long vnpayTranId = Convert.ToInt64(vnpay.GetResponseData("vnp_TransactionNo"));
string vnp_ResponseCode = vnpay.GetResponseData("vnp_ResponseCode");
string vnp_TransactionStatus = vnpay.GetResponseData("vnp_TransactionStatus");
String vnp_SecureHash = Request.QueryString["vnp_SecureHash"];
bool checkSignature = vnpay.ValidateSignature(vnp_SecureHash, vnp_HashSecret);
if (checkSignature)
{
//Cap nhat ket qua GD
//Yeu cau: Truy van vao CSDL cua Merchant => lay ra duoc OrderInfo
//Giả sử OrderInfo lấy ra được như giả lập bên dưới
OrderInfo order = new OrderInfo();//get from DB
order.OrderId = orderId;
order.Amount = 100000;
order.PaymentTranId = vnpayTranId;
order.Status = "0"; //0: Cho thanh toan,1: da thanh toan,2: GD loi
//Kiem tra tinh trang Order
if (order != null)
{
if (order.Amount == vnp_Amount) {
if (order.Status == "0")
{
if (vnp_ResponseCode == "00" && vnp_TransactionStatus == "00")
{
//Thanh toan thanh cong
log.InfoFormat("Thanh toan thanh cong, OrderId={0}, VNPAY TranId={1}", orderId,
vnpayTranId);
order.Status = "1";
}
else
{
//Thanh toan khong thanh cong. Ma loi: vnp_ResponseCode
// displayMsg.InnerText = "Có lỗi xảy ra trong quá trình xử lý.
Mã lỗi: " + vnp_ResponseCode;
log.InfoFormat("Thanh toan loi, OrderId={0}, VNPAY TranId={1},ResponseCode={2}",
orderId, vnpayTranId, vnp_ResponseCode);
order.Status = "2";
}
//Thêm code Thực hiện cập nhật vào Database
//Update Database
returnContent = "{\"RspCode\":\"00\",\"Message\":\"Confirm Success\"}";
}
else
{
returnContent = "{\"RspCode\":\"02\",\"Message\":\"Order already confirmed\"}";
}
}
else
{
returnContent = "{\"RspCode\":\"04\",\"Message\":\"invalid amount\"}";
}
}
else
{
returnContent = "{\"RspCode\":\"01\",\"Message\":\"Order not found\"}";
}
}
else
{
log.InfoFormat("Invalid signature, InputData={0}", Request.RawUrl);
returnContent = "{\"RspCode\":\"97\",\"Message\":\"Invalid signature\"}";
}
}
else
{
returnContent = "{\"RspCode\":\"99\",\"Message\":\"Input data required\"}";
}
Response.ClearContent();
Response.Write(returnContent);
Response.End();
}
def payment_ipn(request):
inputData = request.GET
Đơn vị cập nhật lại thư viện "vnpay.py". Trong thư viện này VNPAY đã thay đổi thuật toán mã hóa MD5 hoặc SHA256
sang HMACSHA512
Tải "vnpay.py" về tại đây
if inputData:
vnp = vnpay()
vnp.responseData = inputData.dict()
order_id = inputData['vnp_TxnRef']
amount = inputData['vnp_Amount']
order_desc = inputData['vnp_OrderInfo']
vnp_TransactionNo = inputData['vnp_TransactionNo']
vnp_ResponseCode = inputData['vnp_ResponseCode']
vnp_TmnCode = inputData['vnp_TmnCode']
vnp_PayDate = inputData['vnp_PayDate']
vnp_BankCode = inputData['vnp_BankCode']
vnp_CardType = inputData['vnp_CardType']
if vnp.validate_response(settings.VNPAY_HASH_SECRET_KEY):
# Check & Update Order Status in your Database
# Your code here
firstTimeUpdate = True
totalAmount = True
if totalAmount:
if firstTimeUpdate:
if vnp_ResponseCode == '00':
print('Payment Success. Your code implement here')
else:
print('Payment Error. Your code implement here')
# Return VNPAY: Merchant update success
result = JsonResponse({'RspCode': '00', 'Message': 'Confirm Success'})
else:
# Already Update
result = JsonResponse({'RspCode': '02', 'Message': 'Order Already Update'})
else:
# invalid amount
result = JsonResponse({'RspCode': '04', 'Message': 'invalid amount'})
else:
# Invalid Signature
result = JsonResponse({'RspCode': '97', 'Message': 'Invalid Signature'})
else:
result = JsonResponse({'RspCode': '99', 'Message': 'Invalid request'})
return result
<%
try
{
/* IPN URL: Record payment results from VNPAY
Implementation steps:
Check checksum
Find transactions (vnp_TxnRef) in the database (checkOrderId)
Check the payment status of transactions before updating (checkOrderStatus)
Check the amount (vnp_Amount) of transactions before updating (checkAmount)
Update results to Database
Return recorded results to VNPAY
*/
// ex: PaymnentStatus = 0; pending
// PaymnentStatus = 1; success
// PaymnentStatus = 2; Faile
//Begin process return from VNPAY
Map fields = new HashMap();
Phiên bản 2.0.0, 2.0.1 thay đổi đoạn
for (Enumeration params = request.getParameterNames(); params.hasMoreElements();) {
String fieldName = (String) params.nextElement();
String fieldValue = request.getParameter(fieldName);
if ((fieldValue != null) && (fieldValue.length() > 0))
{
fields.put(fieldName, fieldValue);
}
}
Thành:
for (Enumeration params = request.getParameterNames(); params.hasMoreElements();) {
String fieldName = URLEncoder.encode((String) params.nextElement(), StandardCharsets.US_ASCII.toString());
String fieldValue = URLEncoder.encode(request.getParameter(fieldName), StandardCharsets.US_ASCII.toString());
if ((fieldValue != null) && (fieldValue.length() > 0)) {
fields.put(fieldName, fieldValue);
}
}
String vnp_SecureHash = request.getParameter("vnp_SecureHash");
if (fields.containsKey("vnp_SecureHashType"))
{
fields.remove("vnp_SecureHashType");
}
if (fields.containsKey("vnp_SecureHash"))
{
fields.remove("vnp_SecureHash");
}
// Check checksum
String signValue = Config.hashAllFields(fields);
Trong đó Config.hashAllFields là:
public static String hashAllFields(Map fields) {
// create a list and sort it
List fieldNames = new ArrayList(fields.keySet());
Collections.sort(fieldNames);
// create a buffer for the md5 input and add the secure secret first
StringBuilder sb = new StringBuilder();
//sb.append(com.vnpay.common.Config.vnp_HashSecret);
Iterator itr = fieldNames.iterator();
while (itr.hasNext()) {
String fieldName = (String) itr.next();
String fieldValue = (String) fields.get(fieldName);
if ((fieldValue != null) && (fieldValue.length() > 0)) {
sb.append(fieldName);
sb.append("=");
sb.append(fieldValue);
}
if (itr.hasNext()) {
sb.append("&");
}
}
//return Sha256(sb.toString());
return hmacSHA512(vnp_HashSecret,sb.toString());
}
if (signValue.equals(vnp_SecureHash))
{
boolean checkOrderId = true; // vnp_TxnRef exists in your database
boolean checkAmount = true; // vnp_Amount is valid (Check vnp_Amount VNPAY returns compared to the
amount of the code (vnp_TxnRef) in the Your database).
boolean checkOrderStatus = true; // PaymnentStatus = 0 (pending)
if(checkOrderId)
{
if(checkAmount)
{
if (checkOrderStatus)
{
if ("00".equals(request.getParameter("vnp_ResponseCode")))
{
//Here Code update PaymnentStatus = 1 into your Database
}
else
{
// Here Code update PaymnentStatus = 2 into your Database
}
out.print ("{\"RspCode\":\"00\",\"Message\":\"Confirm Success\"}");
}
else
{
out.print("{\"RspCode\":\"02\",\"Message\":\"Order already confirmed\"}");
}
}
else
{
out.print("{\"RspCode\":\"04\",\"Message\":\"Invalid Amount\"}");
}
}
else
{
out.print("{\"RspCode\":\"01\",\"Message\":\"Order not Found\"}");
}
}
else
{
out.print("{\"RspCode\":\"97\",\"Message\":\"Invalid Checksum\"}");
}
}
catch(Exception e)
{
out.print("{\"RspCode\":\"99\",\"Message\":\"Unknow error\"}");
}
%>
router.get('/vnpay_ipn', function (req, res, next) {
var vnp_Params = req.query;
var secureHash = vnp_Params['vnp_SecureHash'];
delete vnp_Params['vnp_SecureHash'];
delete vnp_Params['vnp_SecureHashType'];
vnp_Params = sortObject(vnp_Params);
var config = require('config');
var secretKey = config.get('vnp_HashSecret');
var querystring = require('qs');
Thay đổi đoạn code:
var signData = secretKey + querystring.stringify(vnp_Params, { encode: false });
var md5 = require('md5');
var checkSum = md5(signData);
hoặc
var signData = secretKey + querystring.stringify(vnp_Params, { encode: false });
var md5 = require('sha256');
var checkSum = sha256(signData);
Chuyển thành:
var signData = querystring.stringify(vnp_Params, { encode: false });
var crypto = require("crypto");
var hmac = crypto.createHmac("sha512", secretKey);
var signed = hmac.update(new Buffer(signData, 'utf-8')).digest("hex");
if(secureHash === signed){
var orderId = vnp_Params['vnp_TxnRef'];
var rspCode = vnp_Params['vnp_ResponseCode'];
//Kiem tra du lieu co hop le khong, cap nhat trang thai don hang va gui ket qua cho VNPAY theo dinh dang duoi
res.status(200).json({RspCode: '00', Message: 'success'})
}
else {
res.status(200).json({RspCode: '97', Message: 'Fail checksum'})
}
});
Cài đặt Code Return URL
Dữ liệu VNPAY trả về bằng cách chuyển hướng trình duyệt web của khách hàng theo địa chỉ web mà Merchant cung cấp khi gửi yêu cầu thanh toán.
Trên URL này mang thông tin kết quả thanh toán của khách hàng.
VNPAY trả về kết quả thanh toán URL có dạng:
https://{domain}/ReturnUrl?vnp_Amount=1000000& vnp_BankCode=NCB& vnp_BankTranNo=20170829152730& vnp_CardType=ATM& vnp_OrderInfo=Thanh+toan+don+hang+thoi+gian%3A+2017-08-29+15%3A27%3A02& vnp_PayDate=20170829153052& vnp_ResponseCode=00& vnp_TmnCode=2QXUI4J4& vnp_TransactionNo=12996460& vnp_TxnRef=23597& vnp_SecureHashType=SHA256& vnp_SecureHash=20081f0ee1cc6b524e273b6d4050fefd
Trong đó https://{domain}/ReturnUrl
là URL nhận kết quả hệ thống gửi sang VNPAY theo URL thanh toán qua tham sốvnp_ReturnUrl
Danh sách tham số
Giống với danh sách tham số gửi về địa chỉ IPN URL
Lưu ý
Chuyển đổi tương tự như đầu IPN URL
Code cài đặt
require_once("./config.php");
$vnp_SecureHash = $_GET['vnp_SecureHash'];
$inputData = array();
foreach ($_GET as $key => $value) {
if (substr($key, 0, 4) == "vnp_") {
$inputData[$key] = $value;
}
}
unset($inputData['vnp_SecureHash']);
ksort($inputData);
$i = 0;
$hashData = "";
foreach ($inputData as $key => $value) {
if ($i == 1) {
$hashData = $hashData . '&' . urlencode($key) . "=" . urlencode($value);
} else {
$hashData = $hashData . urlencode($key) . "=" . urlencode($value);
$i = 1;
}
}
$secureHash = hash_hmac('sha512', $hashData, $vnp_HashSecret);
if ($secureHash == $vnp_SecureHash) {
if ($_GET['vnp_ResponseCode'] == '00') {
echo "GD Thanh cong ";
}
else {
echo "GD Khong thanh cong ";
}
} else {
echo "Chu ky khong hop le ";
}
private static readonly
ILog log =
LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected void Page_Load(object sender, EventArgs e)
{
log.InfoFormat("Begin VNPAY Return, URL={0}", Request.RawUrl);
if (Request.QueryString.Count > 0)
{
string vnp_HashSecret = ConfigurationManager.AppSettings["vnp_HashSecret"]; //Chuoi bi mat
var vnpayData = Request.QueryString;
VnPayLibrary vnpay = new VnPayLibrary();
foreach (string s in vnpayData)
{
//get all querystring data
if (!string.IsNullOrEmpty(s) && s.StartsWith("vnp_"))
{
vnpay.AddResponseData(s, vnpayData[s]);
}
}
//vnp_TxnRef: Ma don hang merchant gui VNPAY tai command=pay
//vnp_TransactionNo: Ma GD tai he thong VNPAY
//vnp_ResponseCode:Response code from VNPAY: 00: Thanh cong, Khac 00: Xem tai lieu
//vnp_SecureHash: HmacSHA512 cua du lieu tra ve
long orderId = Convert.ToInt64(vnpay.GetResponseData("vnp_TxnRef"));
long vnpayTranId = Convert.ToInt64(vnpay.GetResponseData("vnp_TransactionNo"));
string vnp_ResponseCode = vnpay.GetResponseData("vnp_ResponseCode");
string vnp_TransactionStatus = vnpay.GetResponseData("vnp_TransactionStatus");
String vnp_SecureHash = Request.QueryString["vnp_SecureHash"];
String TerminalID = Request.QueryString["vnp_TmnCode"];
long vnp_Amount = Convert.ToInt64(vnpay.GetResponseData("vnp_Amount"))/100;
String bankCode = Request.QueryString["vnp_BankCode"];
bool checkSignature = vnpay.ValidateSignature(vnp_SecureHash, vnp_HashSecret);
if (checkSignature)
{
if (vnp_ResponseCode == "00" && vnp_TransactionStatus == "00")
{
//Thanh toan thanh cong
displayMsg.InnerText = "Giao dịch được thực hiện thành công. Cảm ơn quý khách đã sử
dụng dịch vụ";
log.InfoFormat("Thanh toan thanh cong, OrderId={0}, VNPAY TranId={1}", orderId,
vnpayTranId);
}
else
{
//Thanh toan khong thanh cong. Ma loi: vnp_ResponseCode
displayMsg.InnerText = "Có lỗi xảy ra trong quá trình xử lý.Mã lỗi: " + vnp_ResponseCode;
log.InfoFormat("Thanh toan loi, OrderId={0}, VNPAY TranId={1},ResponseCode={2}", orderId,
vnpayTranId, vnp_ResponseCode);
}
displayTmnCode.InnerText = "Mã Website (Terminal ID):" + TerminalID;
displayTxnRef.InnerText = "Mã giao dịch thanh toán:" + orderId.ToString();
displayVnpayTranNo.InnerText = "Mã giao dịch tại VNPAY:" + vnpayTranId.ToString();
displayAmount.InnerText = "Số tiền thanh toán (VND):" + vnp_Amount.ToString();
displayBankCode.InnerText = "Ngân hàng thanh toán:" + bankCode;
}
else
{
log.InfoFormat("Invalid signature, InputData={0}", Request.RawUrl);
displayMsg.InnerText = "Có lỗi xảy ra trong quá trình xử lý";
}
}
}
def payment_return(request):
inputData = request.GET
if inputData:
vnp = vnpay()
vnp.responseData = inputData.dict()
order_id = inputData['vnp_TxnRef']
amount = int(inputData['vnp_Amount']) / 100
order_desc = inputData['vnp_OrderInfo']
vnp_TransactionNo = inputData['vnp_TransactionNo']
vnp_ResponseCode = inputData['vnp_ResponseCode']
vnp_TmnCode = inputData['vnp_TmnCode']
vnp_PayDate = inputData['vnp_PayDate']
vnp_BankCode = inputData['vnp_BankCode']
vnp_CardType = inputData['vnp_CardType']
if vnp.validate_response(settings.VNPAY_HASH_SECRET_KEY):
if vnp_ResponseCode == "00":
return render(request, "payment_return.html", {"title": "Kết quả thanh toán",
"result": "Thành công", "order_id": order_id,
"amount": amount,
"order_desc": order_desc,
"vnp_TransactionNo": vnp_TransactionNo,
"vnp_ResponseCode": vnp_ResponseCode})
else:
return render(request, "payment_return.html", {"title": "Kết quả thanh toán",
"result": "Lỗi", "order_id": order_id,
"amount": amount,
"order_desc": order_desc,
"vnp_TransactionNo": vnp_TransactionNo,
"vnp_ResponseCode": vnp_ResponseCode})
else:
return render(request, "payment_return.html",
{"title": "Kết quả thanh toán", "result": "Lỗi", "order_id": order_id, "amount": amount,
"order_desc": order_desc, "vnp_TransactionNo": vnp_TransactionNo,
"vnp_ResponseCode": vnp_ResponseCode, "msg": "Sai checksum"})
else:
return render(request, "payment_return.html", {"title": "Kết quả thanh toán", "result": ""})
<%
//Begin process return from VNPAY
Map fields = new HashMap ();
for ( Enumeration params = request . getParameterNames (); params . hasMoreElements ();) {
String fieldName = ( String ) params . nextElement ();
String fieldValue = request . getParameter ( fieldName );
if (( fieldValue != null ) && ( fieldValue . length () > 0 )) {
fields . put ( fieldName , fieldValue );
}
}
String vnp_SecureHash = request . getParameter ( "vnp_SecureHash" );
if ( fields . containsKey ( "vnp_SecureHashType" )) {
fields . remove ( "vnp_SecureHashType" );
}
if ( fields . containsKey ( "vnp_SecureHash" )) {
fields . remove ( "vnp_SecureHash" );
}
String signValue = Config . hashAllFields ( fields );
%>
<%
if ( signValue . equals ( vnp_SecureHash )) {
if ( "00" . equals ( request . getParameter ( "vnp_ResponseCode" ))) {
out . print ( "GD Thanh cong" );
} else {
out . print ( "GD Khong thanh cong" );
}
} else {
out . print ( "Chu ky khong hop le" );
}
%>
router.get('/vnpay_return', function (req, res, next) {
var vnp_Params = req.query;
var secureHash = vnp_Params['vnp_SecureHash'];
delete vnp_Params['vnp_SecureHash'];
delete vnp_Params['vnp_SecureHashType'];
vnp_Params = sortObject(vnp_Params);
var config = require('config');
var tmnCode = config.get('vnp_TmnCode');
var secretKey = config.get('vnp_HashSecret');
var querystring = require('qs');
var signData = querystring.stringify(vnp_Params, { encode: false });
var crypto = require("crypto");
var hmac = crypto.createHmac("sha512", secretKey);
var signed = hmac.update(new Buffer(signData, 'utf-8')).digest("hex");
if(secureHash === signed){
//Kiem tra xem du lieu trong db co hop le hay khong va thong bao ket qua
res.render('success', {code: vnp_Params['vnp_ResponseCode']})
} else{
res.render('success', {code: '97'})
}
});
Bảng mã lỗi của hệ thống
Mã lỗi
Mô tả
Bảng mã lỗi vnp_TransactionStatus
00
Giao dịch thành công
01
Giao dịch chưa hoàn tất
02
Giao dịch bị lỗi
04
Giao dịch đảo (Khách hàng đã bị trừ tiền tại Ngân hàng nhưng GD chưa thành
công ở VNPAY)
05
VNPAY đang xử lý giao dịch này (GD hoàn tiền)
06
VNPAY đã gửi yêu cầu hoàn tiền sang Ngân hàng (GD hoàn tiền)
07
Giao dịch bị nghi ngờ gian lận
09
GD Hoàn trả bị từ chối
Mã lỗi
Mô tả
vnp_ResponseCode VNPAY phản hồi qua IPN và Return URL:
00
Giao dịch thành công
07
Trừ tiền thành công. Giao dịch bị nghi ngờ (liên quan tới lừa đảo, giao dịch bất thường).
09
Giao dịch không thành công do: Thẻ/Tài khoản của khách hàng chưa đăng ký dịch vụ InternetBanking tại ngân hàng.
10
Giao dịch không thành công do: Khách hàng xác thực thông tin thẻ/tài khoản không đúng quá 3 lần
11
Giao dịch không thành công do: Đã hết hạn chờ thanh toán. Xin quý khách vui lòng thực hiện lại giao dịch.
12
Giao dịch không thành công do: Thẻ/Tài khoản của khách hàng bị khóa.
13
Giao dịch không thành công do Quý khách nhập sai mật khẩu xác thực giao dịch (OTP). Xin quý khách vui lòng thực hiện lại giao dịch.
24
Giao dịch không thành công do: Khách hàng hủy giao dịch
51
Giao dịch không thành công do: Tài khoản của quý khách không đủ số dư để thực hiện giao dịch.
65
Giao dịch không thành công do: Tài khoản của Quý khách đã vượt quá hạn mức giao dịch trong ngày.
75
Ngân hàng thanh toán đang bảo trì.
79
Giao dịch không thành công do: KH nhập sai mật khẩu thanh toán quá số lần quy định. Xin quý khách vui lòng thực hiện lại giao dịch
99
Các lỗi khác (lỗi còn lại, không có trong danh sách mã lỗi đã liệt kê)