Xin chào mọi người, lâu lắm rồi mới có thời gian để chia sẽ một số điều bổ ích mình học được sau một quãng thời gian làm việc. Hôm này mình sẽ giới thiệu với mọi người về cổng thanh toán Paypay (Paypay != Paypal).
Như mọi người cũng biết Momo là một cổng thanh toán rất phổ biến hiện tại tại Việt Nam, tương tự như thế Paypay cũng là một cổng thanh toán phổ biến hàng đầu tại Nhật Bản. Vừa qua dự án Yoseka đã tích hợp thêm tính năng thanh toán bằng Paypay vào, gặp phải một số khó khăn nhất định nhưng cuối cùng cũng đã hoàn thành. Sau đây là một số chia sẻ của mình về cách thức triển khai thanh toán Paypay trong một dự án Laravel (Paypay cung cấp cho cũng ta 3 Payment Api chính là: Web Payment, App Payment, Server Call trong chia sẻ lần này mình chỉ tập trung vào phần Web Payment là phần được chúng ta thường xuyên sử dụng).
- Trong Web Payment lại chia thành 2 loại: Smart Payment và Web Payment (Cơ bản thì Smart Payment sau khi người dùng đăng nhập lần đầu nó sẽ lưu lại trình duyệt và cookie trong 90 ngày và trong 90 ngày đó khi thanh toán trên trình duyệt đó người dùng sẽ không cần đăng nhập lại nhưng có một vấn đề nho nhỏ là document của Paypay trong phần Smart Payment không có tài liệu về tích hợp nó trong PHP và tài liệu search trên gg cũng gần như không có 🙁 ). Và vì thế nên bài viết này sẽ tập trung vào phần Web Payment trong mục Web Payment (Phần này tài liệu khá đầy đủ và dễ tiếp cận).
Bắt đầu nhé: (Web Payment trong Web Payment)
- Đầu tiên để làm việc với Paypay bằng PHP chúng ta cần cài Paypay OPA PHP SDK (composer require paypayopa/php-sdk) và lưu ý nó hoạt động với php 7.x nhé.
- Trước hết mình sẽ tìm hiểu về luồng dữ liệu của nó:
Như mình hiểu đơn giản luồng nó sẽ như này: Client -> Gửi request yêu cầu thanh toán về phía Backend của mình -> Backend của mình tiếp nhận tạo các dữ liệu cần thiết và gửi một request về phía Backend của Paypay -> Backend của Paypay tiếp nhận xử lý và trả ra các dữ liệu sau khi khởi tạo thanh toán cho phía Backend của mình -> Backend của mình lại trả tiếp dữ liệu này cho phía Client -> Từ dữ liệu nhận được Client sẽ thực hiện mở ra trang thay toán của Paypay -> Hệ thống của Paypay xử lý thanh toán và redirect về Client (url redirect mình sẽ config lúc khởi tạo thanh toán) -> Cuối cùng từ Client mình có thể thực hiện các yêu cầu như Huỷ, Hoàn Tiền, Lấy chi tiết thanh toán dựa trên merchantId.
- Cụ thể như này:
+ B1: Khởi tạo đối tượng Client:
use PayPay\OpenPaymentAPI\Client;
`use PayPay\OpenPaymentAPI\Client;
$client = new Client([
'API_KEY' => 'YOUR_API_KEY',
'API_SECRET'=>'YOUR_API_SECRET',
'MERCHANT_ID'=>'YOUR_MERCHANT_ID'
],false);`
** Lưu ý: với môi trường test sẽ set tham số thứ 2 là 'false', production set là 'true'
B2: Tạo thanh toán
Đây là các tham số mình cần lưu ý khi khởi tạo thanh toán, đa số khá dễ hiểu, trong quá trình tích hợp thì có một số cái mình có thể lưu ý như sau:
- isAuthorization: Nếu là false thì sau khi thanh toán tiền sẽ về luôn ví của người bán, nếu là true thì sau khi thanh toán tiền sẽ không về luôn ví người bán mà ở trong trạng thái chờ capture, và chỉ khi người bán capture thanh toán đó thì tiền mới về ví người bán.
- userAgent: Nó cũng khá hữu ích, khi tham số userAgent được cung cấp, trên thiết bị di động sau thanh toán PayPay sẽ cố gắng mở trình duyệt mà trang web người bán đang sử dụng.
Mình sẽ note 2 cái mình thấy khá hay ở đây thôi, còn lại thắc mắc nào mọi người cứ để lại bên phía dưới comment nhé.
`use PayPay\OpenPaymentAPI\Models\CreateQrCodePayload;
use PayPay\OpenPaymentAPI\Models\OrderItem;
/*
.....initialize SDK
*/
// setup payment object
$CQCPayload = new CreateQrCodePayload();
// Set merchant pay identifier
$CQCPayload->setMerchantPaymentId("YOUR_TRANSACTION_ID");
// Log time of request
$CQCPayload->setRequestedAt();
// Indicate you want QR Code
$CQCPayload->setCodeType("ORDER_QR");
// Provide order details for invoicing
$OrderItems = [];
$OrderItems[] = (new OrderItem())
->setName('Cake')
->setQuantity(1)
->setUnitPrice('amount' => 20, 'currency' => 'JPY']);
$CQCPayload->setOrderItems($OrderItems);
// Save Cart totals
$amount = [
"amount" => 1,
"currency" => "JPY"
];
$CQCPayload->setAmount($amount);
// Configure redirects
$CQCPayload->setRedirectType('WEB_LINK');
$CQCPayload->setRedirectUrl($_SERVER['SERVER_NAME']);
// Get data for QR code
$response = $client->code->createQRCode($CQCPayload);
$data = $response['data'];`
B3: Các thực hiện có thể làm sau khi thanh toán với Paypay
Xem chi tiết thanh toán: (detail)
$response = $client->code->getPaymentDetails('MERCHANT_PAYMENT_ID');
$data = $response['data'];
Huỷ thanh toán: (cancel)
// Calling the method to cancel a Payment
$response = $client->payment->cancelPayment('merchantPaymentId');
// Printing if the method call was SUCCESS
var_dump($response['resultInfo']['code']);
Hoàn lại tiền: (refund)
$amount = [
"amount" => 1,
"currency" => "JPY"
];
$RPPayload = new RefundPaymentPayload();
$RPPayload
->setMerchantRefundId("UNIQUE_REFUND_ID")
->setPaymentId("PAYPAY_PAYMENT_ID")
->setAmount($amount)
->setRequestedAt();//Leave empty for current time and pass DateTime specify exact time
$resp = $this->client->refund->refundPayment($RPPayload);
Capture thanh toán (Tại sao có capture thì mọi người đoạn phần trên nhé isAuthorize)
use PayPay\OpenPaymentAPI\Models\CapturePaymentAuthPayload;
/*
.....initialize SDK
*/
// setup payment object
$CAPayload = new CapturePaymentAuthPayload();
$CAPayload->setMerchantPaymentId("YOUR_TRANSACTION_ID");
$amount = [
"amount" => 1,
"currency" => "JPY"
];
$CAPayload->setAmount($amount);
Huỷ bỏ uỷ quyền thanh toán: (revert)
`use PayPay\OpenPaymentAPI\Models\RevertAuthPayload;
/*
.....initialize SDK
*/
// setup payment object
$RAPayload = new RevertAuthPayload();
$RAPayload->setMerchantRevertId("UNIQUE_REVERT_ID");
$RAPayload->setPaymentId("MERCHANT_PAYMENT_ID");
$RAPayload->setRequestedAt();
$RAPayload->setReason("REASON_FOR_REFUND");
$response = $client->payment->revertAuth($RAPayload)`
B4: Xử lý kickback
Sau khi thực hiện thanh toán thì Paypay sẽ thực hiện kickback về cho mình dưới dạng method post, và từ kickback ấy mình có thể thực hiện các xử lý tạo payment, thông báo thành công, thất bại. Về dữ liệu kickback trả về mọi người có thể đặt Log hoặc lên document của Paypay để xem cụ thể.
*Phần cuối cùng quan trọng lưu ý đặc biệt:**
- Paypay cho 3 tài khoản test mode nên hãy thay phiên nhau dùng 3 tài khoản trên, tránh dùng 1 tài khoản thanh toán liên tục nhiều lần Paypay có thể sẽ báo lỗi.
- Test mode của Paypay trong quá trình mình làm rất hay bị lỗi nên nếu đang thanh toán bình thường phát sinh lỗi thì xem xem nó là lỗi của code hay lỗi của bên phía Paypay (thường thì các lỗi bên phía Paypay sẽ được khắc phục sau tầm 1h - 6h)
- Config webhook của test mode có thể config được trong mục Open Api Configurations nhưng để config được trên product thì phải contact với Paypay để config domain, IP (Nếu không config sẽ bị lỗi thường là 500 Server Paypay Not Authorize);
- Nếu lỡ may IP của bạn bị thay đổi thì phải liên hệ lại với Paypay để đăng ký lại ngay tránh lỗi kéo dài.
- Kick back về sẽ có 2 dạng method một là Get 2 là Post và để xử lý dữ liệu mình chỉ dùng Post thôi nhé, Get sẽ xuất hiện khi mình truyền redirect_url lúc khởi tạo thanh toán.
Cảm ơn anh Tú, anh Đồng, anh Long đã support nhiệt tình để em có thể tìm hiểu được một cách tốt nhất về hệ thống thanh toán này. Sorry các anh vì nhiều lúc quá báo.
Mong rằng bài viết có thể giúp ích cho mọi người sau này, chúc mọi người một ngày đầu tuần vui vẻ!
Thanks for reading!!!