Hướng dẫn tích hợp Cổng thanh toán VNPAY

Tài liệu này sẽ hướng dẫn các lập trình viên của Website TMĐT tích hợp Cổng thanh toán VNPAY để xử lý giao dịch Thanh toán trực tuyến cho khách hàng

Tạo URL Thanh toán

URL Thanh toán là địa chỉ URL mang thông tin thanh toán.
Website TMĐT gửi sang Cổng thanh toán VNPAY các thông tin này khi xử lý giao dịch thanh toán trực tuyến cho Khách mua hàng.
URL có dạng:

http://sandbox.vnpayment.vn/paymentv2/vpcpay.html?vnp_Amount=10000000&vnp_BankCode=NCB&vnp_Command=pay&vnp_CreateDate=20170829103111&vnp_CurrCode=VND&vnp_IpAddr=172.16.68.68&vnp_Locale=vn&vnp_Merchant=DEMO&vnp_OrderInfo=Nap+tien+cho+thue+bao+0123456789.+So+tien+100%2c000&vnp_OrderType=topup&vnp_ReturnUrl=http%3a%2f%2fsandbox.vnpayment.vn%2ftryitnow%2fHome%2fVnPayReturn&vnp_TmnCode=2QXUI4J4&vnp_TxnRef=23554&vnp_Version=2&vnp_SecureHashType=SHA256&vnp_SecureHash=e6ce09ae6695ad034f8b6e6aadf2726f

Danh sách tham số

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.0.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 Alpha[3,20] Tùy chọn Mã Ngân hàng thanh toán. Ví dụ: NCB
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] Tùy chọn 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ụ: http://domain.vn/VnPayReturn
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_SecureHashType Alphanumeric[3,10] Bắt buộc Loại mã băm sử dụng: MD5, SHA256
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 và MD5. Ví dụ:e6ce09ae6695ad034f8b6e6aadf2726f

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 bỏ trống, khách hàng sẽ chọ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 TMĐT), Tham khảo giá trị tại Bảng mã Ngân hàng
  • 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
//Tải code demo tại: https://goo.gl/4mjkd2

$vnp_Url = "http://sandbox.vnpayment.vn/paymentv2/vpcpay.html";
$vnp_Returnurl = "http://localhost/vnpay_php/vnpay_return.php";
$vnp_TmnCode = "";//Mã website tại VNPAY 
$vnp_HashSecret = ""; //Chuỗi bí mật

$vnp_TxnRef = date('YmdHis');//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['orderDesc'];
$vnp_OrderType = $_POST['ordertype'];
$vnp_Amount = $_POST['amount'] * 100;
$vnp_Locale = $_POST['language'];
$vnp_IpAddr = $_SERVER['REMOTE_ADDR'];
$inputData = array(
    "vnp_Version" => "2.0.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,    
);
ksort($inputData);
$query = "";
$i = 0;
$hashdata = "";
foreach ($inputData as $key => $value) {
    if ($i == 1) {
        $hashdata .= '&' . $key . "=" . $value;
    } else {
        $hashdata .= $key . "=" . $value;
        $i = 1;
    }
    $query .= urlencode($key) . "=" . urlencode($value) . '&';
}

$vnp_Url = $vnp_Url . "?" . $query;
if (isset($vnp_HashSecret)) {
    $vnpSecureHash = hash('sha256',$vnp_HashSecret . $hashdata);
    $vnp_Url .= 'vnp_SecureHashType=SHA256&vnp_SecureHash=' . $vnpSecureHash;
}
?>
//Tải code demo tại: https://goo.gl/6SVHAU

private static readonly ILog log =
          LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);        

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;
    order.Amount = Convert.ToInt64(txtAmount.Text);
    order.OrderDesc = txtOrderDesc.Text;
    order.CreatedDate = DateTime.Now;
    string locale = cboLanguage.SelectedItem.Value;
    //Build URL for VNPAY
    VnPayLibrary vnpay = new VnPayLibrary();

    vnpay.AddRequestData("vnp_Version", "2.0.0");
    vnpay.AddRequestData("vnp_Command", "pay");
    vnpay.AddRequestData("vnp_TmnCode", vnp_TmnCode);
    vnpay.AddRequestData("vnp_Amount", (order.Amount * 100).ToString());
    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", order.OrderDesc);
    vnpay.AddRequestData("vnp_OrderType", orderCategory.SelectedItem.Value); //default value: other
    vnpay.AddRequestData("vnp_ReturnUrl", vnp_Returnurl);
    vnpay.AddRequestData("vnp_TxnRef", order.OrderId.ToString());

    string paymentUrl = vnpay.CreateRequestUrl(vnp_Url, vnp_HashSecret);
    log.InfoFormat("VNPAY URL: {0}", paymentUrl);
    Response.Redirect(paymentUrl);
}
#Tải code demo tại: https://goo.gl/Zby37L 
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
            vnp = vnpay()
            vnp.requestData['vnp_Version'] = '2.0.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')  # 20150410063022
            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)
            if request.is_ajax():
                # Show VNPAY Popup
                result = JsonResponse({'code': '00', 'Message': 'Init Success', 'data': vnpay_payment_url})
                return result
            else:
                # Redirect to VNPAY
                return redirect(vnpay_payment_url)
        else:
            print("Form input not validate")
    else:
        return render(request, "payment.html", {"title": "Thanh toán"})


# Hàm tạo URL thanh toán
class vnpay:
    requestData = {}
    responseData = {}

    def get_payment_url(self, vnpay_payment_url, secret_key):
        inputData = sorted(self.requestData.items())
        queryString = ''
        hasData = ''
        seq = 0
        for key, val in inputData:
            if seq == 1:
                queryString = queryString + "&" + key + '=' + urlquote(val)
                hasData = hasData + "&" + str(key) + '=' + str(val)
            else:
                seq = 1
                queryString = key + '=' + urlquote(val)
                hasData = str(key) + '=' + str(val)

        hashValue = self.__md5(secret_key + hasData)
        return vnpay_payment_url + "?" + queryString + '&vnp_SecureHashType=SHA256&vnp_SecureHash=' + hashValue

    def validate_response(self, secret_key):
        vnp_SecureHash = self.responseData['vnp_SecureHash']
        # Remove hash params
        if 'vnp_SecureHash' in self.responseData.keys():
            self.responseData.pop('vnp_SecureHash')

        if 'vnp_SecureHashType' in self.responseData.keys():
            self.responseData.pop('vnp_SecureHashType')
        # self.responseData.pop('vnp_SecureHash', None)
        # self.responseData.pop('vnp_SecureHashType',None)
        inputData = sorted(self.responseData.items())
        hasData = ''
        seq = 0

        for key, val in inputData:
            if str(key).startswith('vnp_'):
                if seq == 1:
                    hasData = hasData + "&" + str(key) + '=' + str(val)
                else:
                    seq = 1
                    hasData = str(key) + '=' + str(val)
        hashValue = self.__md5(secret_key + hasData)

        print(
            'Validate debug, HashData:' + secret_key + hasData + "\n HashValue:" + hashValue + "\nInputHash:" + vnp_SecureHash)

        return vnp_SecureHash == hashValue

    def __md5(self, input):
        byteInput = input.encode('utf-8')
        return hashlib.md5(byteInput).hexdigest()
		
//Tải code demo tại: https://goo.gl/nwY9mj
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String vnp_Version = "2.0.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;

        String vnp_TransactionNo = vnp_TxnRef;
        String vnp_hashSecret = Config.vnp_HashSecret;

        int amount = Integer.parseInt(req.getParameter("amount")) * 100;
        Map<String, String> vnp_Params = new HashMap<>();
        vnp_Params.put("vnp_Version", vnp_Version);
        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);

        Date dt = new Date();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        String dateString = formatter.format(dt);
        String vnp_CreateDate = dateString;
        String vnp_TransDate = vnp_CreateDate;
        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();
        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('&');
                }
            }
        }
        String queryUrl = query.toString();
        String vnp_SecureHash = Config.Sha256(Config.vnp_HashSecret + hashData.toString());
        //System.out.println("HashData=" + hashData.toString());
        queryUrl += "&vnp_SecureHashType=SHA256&vnp_SecureHash=" + vnp_SecureHash;
        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));
    }	
//Tải code demo tại: https://goo.gl/mHqyGY

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 = 'vn';
    var currCode = 'VND';
    var vnp_Params = {};
    vnp_Params['vnp_Version'] = '2';
    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;
    vnp_Params['vnp_BankCode'] = bankCode;

    vnp_Params = sortObject(vnp_Params);

    var querystring = require('qs');
    var signData = secretKey + querystring.stringify(vnp_Params, { encode: false });

    var sha256 = require('sha256');

    var secureHash = sha256(signData);

    vnp_Params['vnp_SecureHashType'] =  'SHA256';
    vnp_Params['vnp_SecureHash'] = secureHash;
    vnpUrl += '?' + querystring.stringify(vnp_Params, { encode: true });

    //Neu muon dung Redirect thi dong dong ben duoi
    res.status(200).json({code: '00', data: vnpUrl})
    //Neu muon dung Redirect thi mo dong ben duoi va dong dong ben tren
    //res.redirect(vnpUrl)
});
function sortObject(o) {
    var sorted = {},
        key, a = [];

    for (key in o) {
        if (o.hasOwnProperty(key)) {
            a.push(key);
        }
    }

    a.sort();

    for (key = 0; key < a.length; key++) {
        sorted[a[key]] = o[a[key]];
    }
    return sorted;
}

Code IPN URL

  • Đây là địa chỉ để nhận kết quả thanh toán từ VNPAY. Kết nối hiện tại sử dụng phương thức GET
  • 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 …)
http://sandbox.vnpayment.vn/tryitnow/Home/VnPayIPN?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ố

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 Alpha[3,20] Bắt buộc Mã Ngân hàng thanh toán. Ví dụ: NCB
vnp_BankTranNo Alpha[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,IB,ACC,QRCODE
vnp_PayDate Numeric[14] Tùy chọn Thời gian thanh toán.
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_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] Bắt buộc Loại mã băm sử dụng: MD5, SHA256
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 định dạng JSON

Code cài đặt

 <?php
/*
 * 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 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();
$data = $_REQUEST;
foreach ($data as $key => $value) {
    if (substr($key, 0, 4) == "vnp_") {
        $inputData[$key] = $value;
    }
}

$vnp_SecureHash = $inputData['vnp_SecureHash'];
unset($inputData['vnp_SecureHashType']);
unset($inputData['vnp_SecureHash']);
ksort($inputData);
$i = 0;
$hashData = "";
foreach ($inputData as $key => $value) {
    if ($i == 1) {
        $hashData = $hashData . '&' . $key . "=" . $value;
    } else {
        $hashData = $hashData . $key . "=" . $value;
        $i = 1;
    }
}
$vnpTranId = $inputData['vnp_TransactionNo']; //Mã giao dịch tại VNPAY
$vnp_BankCode = $inputData['vnp_BankCode']; //Ngân hàng thanh toán
$secureHash = hash('sha256',$vnp_HashSecret . $hashData);
$Status = 0;
$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["Status"] != NULL && $order["Status"] == 0) {
                if ($inputData['vnp_ResponseCode'] == '00') {
                    $Status = 1;
                } else {
                    $Status = 2;
                }
                //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 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'] = '01';
            $returnData['Message'] = 'Order not found';
        }
    } else {
        $returnData['RspCode'] = '97';
        $returnData['Message'] = 'Chu ky khong hop le';
    }
} 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;
        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: SHA256 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_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();
            order.OrderId = orderId;
            order.vnp_TransactionNo = 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.Status == 0)
                {
                    if (vnp_ResponseCode == "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\":\"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
    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 = False
            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 Signature
            result = JsonResponse({'RspCode': '97', 'Message': 'Invalid Signature'})
    else:
        result = JsonResponse({'RspCode': '99', 'Message': 'Invalid request'})

    return 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)) {
        //Kiem tra chu ky OK
        /* Kiem tra trang thai don hang trong DB: checkOrderStatus, 
        - Neu trang thai don hang OK, tien hanh cap nhat vao DB, tra lai cho VNPAY RspCode=00
        - Neu trang thai don hang (da cap nhat roi) => khong cap nhat vao DB, tra lai cho VNPAY RspCode=02
         */
        boolean checkOrderStatus = true;
        if (checkOrderStatus) {
            if ("00".equals(request.getParameter("vnp_ResponseCode"))) {
                //Xu ly thanh toan thanh cong
                // out.print("GD Thanh cong");
            } else {
                //Xu ly thanh toan khong thanh cong
                //  out.print("GD Khong thanh cong");
            }
            out.print ("{\"RspCode\":\"00\",\"Message\":\"Confirm Success\"}");
        } else {
            //Don hang nay da duoc cap nhat roi, Merchant khong cap nhat nua (Duplicate callback)
            out.print("{\"RspCode\":\"02\",\"Message\":\"Order already confirmed\"}");
        }

    } else {
        out.print("{\"RspCode\":\"97\",\"Message\":\"Invalid Checksum\"}");
    }
%>
 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');
    var signData = secretKey + querystring.stringify(vnp_Params, { encode: false });
    
    var sha256 = require('sha256');

    var checkSum = sha256(signData);

    if(secureHash === checkSum){
        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'})
    }
});

function sortObject(o) {
    var sorted = {},
        key, a = [];

    for (key in o) {
        if (o.hasOwnProperty(key)) {
            a.push(key);
        }
    }

    a.sort();

    for (key = 0; key < a.length; key++) {
        sorted[a[key]] = o[a[key]];
    }
    return sorted;
}

Code ReturnURL

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.

http://sandbox.vnpayment.vn/tryitnow/Home/VnPayReturn?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ố

Giống với tham số gửi về địa chỉ IPN URL

Lưu ý

  • URL này chỉ kiểm tra toàn vẹn dữ liệu (checksum) và hiển thị thông báo tới khách hàng
  • Không cập nhật kết quả giao dịch tại địa chỉ này

Code cài đặt

<?php
require_once("./config.php");
$vnp_SecureHash = $_GET['vnp_SecureHash'];
$inputData = array();
foreach ($_GET as $key => $value) {
    $inputData[$key] = $value;
}
unset($inputData['vnp_SecureHashType']);
unset($inputData['vnp_SecureHash']);
ksort($inputData);
$i = 0;
$hashData = "";
foreach ($inputData as $key => $value) {
    if ($i == 1) {
        $hashData = $hashData . '&' . $key . "=" . $value;
    } else {
        $hashData = $hashData . $key . "=" . $value;
        $i = 1;
    }
}

$secureHash = hash('sha256',$vnp_HashSecret . $hashData);
?>
<?php
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: SHA256 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_SecureHash = Request.QueryString["vnp_SecureHash"];

        bool checkSignature = vnpay.ValidateSignature(vnp_SecureHash, vnp_HashSecret);
        if (checkSignature)
        {
            if (vnp_ResponseCode == "00")
            {
                //Thanh toan thanh cong
                displayMsg.InnerText = "Thanh toán thành công";
                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);
            }
        }
        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 = secretKey + querystring.stringify(vnp_Params, { encode: false });

    var sha256 = require('sha256');

    var checkSum = sha256(signData);

    if(secureHash === checkSum){
        //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']})
    }
});

function sortObject(o) {
    var sorted = {},
        key, a = [];

    for (key in o) {
        if (o.hasOwnProperty(key)) {
            a.push(key);
        }
    }

    a.sort();

    for (key = 0; key < a.length; key++) {
        sorted[a[key]] = o[a[key]];
    }
    return sorted;
}

Download Code demo

STT Ngôn ngữ Link download
1 PHP Downloads
2 C# Downloads
3 Python Downloads
4 Java Downloads
5 NodeJs Downloads