文章目錄
- 1、前置
- 2、準備工作
-
- 1、MANEV包:
- 2、擷取Client ID和Secret, 登入位址: https://developer.paypal.com
- 3、擷取測試的賬号密碼:
- 4、登入付款賬戶:登入:https://www.sandbox.paypal.com
- 5、登入接受付款的商戶:登入:https://www.sandbox.paypal.com
- 2、建立訂單
- 3、捕獲訂單
- 4、查詢訂單
- 5、申請退款
- 6、支付成功回調通知
- 7、支付失敗回調通知
- 8:雜談
1、前置
1、案列采用java編寫
2、介紹PayPal訂單整合:
https://developer.paypal.com/docs/integration/direct/payments/orders/
https://developer.paypal.com/docs/api/orders/v2/
3、會對一些可能出現的坑,或者說我碰到的坑進行标記
5、介最後貼圖驗證以及做好後的樣子
6、建立訂單 → 捕獲訂單 → 查詢訂單 → 申請退款
7、代碼已上傳碼雲,如果起到幫助還請star一下位址:https://gitee.com/xmaxm/payments_hodgepodge
2、準備工作
1、MANEV包:
<!-- paypal -->
<dependency>
<groupId>com.paypal.sdk</groupId>
<artifactId>checkout-sdk</artifactId>
<version>1.0.2</version>
</dependency>
2、擷取Client ID和Secret, 登入位址: https://developer.paypal.com

3、擷取測試的賬号密碼:
4、登入付款賬戶:登入:https://www.sandbox.paypal.com
第三步中擷取的賬号密碼, 賬戶錢不夠, 可以從第三步的編輯中為自己添加測試金額
5、登入接受付款的商戶:登入:https://www.sandbox.paypal.com
Unclaimed:這個狀态的原因如下:
https://www.paypal.com/c2/smarthelp/article/why-is-my-paypal-payment-unclaimed-faq1490
無人認領/待處理:如果您的付款尚待處理,則表示收件人尚未接受。有幾種原因可能導緻您的付款待處理。
付款可能有待處理,原因是:
• 收件人尚未注冊PayPal帳戶。
• 您将款項彙入了收件人尚未添加到其PayPal帳戶的電子郵件位址或電話号碼。一旦他們将此資訊添加到他們的帳戶中,錢就會顯示在他們的餘額中。
• 收件人仍在決定是否要接受您的付款。
• 收款人尚未确認其銀行帳戶。
如果您的付款在30天内無人認領/待處理,或者您的付款被拒絕或退款,那麼您将獲得退款
我的原因是:币機關不一緻問題, 因為有匯率的存在, 是以PayPal無法自動收款.
建立訂單時和商戶配置的貨币機關一緻, 就可以直接完成訂單
貨币機關配置:
2、建立訂單
@Override
public CommonResult createOrder(String amount) {
PayPalHttpClient client;
// 設定環境沙盒或生産
if (true) {
client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
} else {
client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
}
// 配置請求參數
OrderRequest orderRequest = new OrderRequest();
orderRequest.checkoutPaymentIntent("CAPTURE");
List<PurchaseUnitRequest> purchaseUnits = new ArrayList<>();
purchaseUnits.add(new PurchaseUnitRequest().amountWithBreakdown(new AmountWithBreakdown().currencyCode(currency).value(amount)));
orderRequest.purchaseUnits(purchaseUnits);
orderRequest.applicationContext(new ApplicationContext().returnUrl(notifyURLSuccess).cancelUrl(notifyURLFail));
OrdersCreateRequest request = new OrdersCreateRequest().requestBody(orderRequest);
HttpResponse<Order> response;
try {
response = client.execute(request);
Order order = response.result();
String token = order.id();
log.debug("payPal 支付操作傳回結果: " + order);
String payHref = null;
String status = order.status();
if (status.equals("CREATED")) {
List<LinkDescription> links = order.links();
for (LinkDescription linkDescription : links) {
if (linkDescription.rel().equals("approve")) {
payHref = linkDescription.href();
}
}
}
Map<String, String> resultMap = new HashMap<String, String>();
resultMap.put("token", token);
resultMap.put("payHref", payHref);
return CommonResult.success("SUCCESS", resultMap);
} catch (IOException ioe) {
if (ioe instanceof HttpException) {
HttpException he = (HttpException) ioe;
log.error("payPal 下單異常: " + ioe);
return CommonResult.failMessage(500, "PayPal支付失敗", he.getMessage());
}
log.error("payPal 下單異常: " + ioe);
return CommonResult.fail(500, "NetworkTimeout");
}
}
請求上面會得到如下結果, 我們請求一下這個連結, 輸入測試賬号密碼進行支付
{
"code": 200,
"message": "SUCCESS",
"data": {
"payHref": "https://www.sandbox.paypal.com/checkoutnow?token=96R506274J980111X",
"token": "96R506274J980111X"
}
}
3、捕獲訂單
@Override
public CommonResult captureOrder(String token) {
PayPalHttpClient client;
// 設定環境沙盒或生産
if (true) {
client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
} else {
client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
}
OrdersCaptureRequest request = new OrdersCaptureRequest(token);
try {
HttpResponse<Order> response = client.execute(request);
Order order = response.result();
String status = order.status();
if (status.equals("COMPLETED")) {
return CommonResult.success("SUCCESS");
}
return CommonResult.success("SUCCESS");
} catch (IOException ioe) {
if (ioe instanceof HttpException) {
HttpException he = (HttpException) ioe;
log.error("payPal 捕獲訂單異常: " + ioe);
return CommonResult.failMessage(500, "PayPal支付捕獲失敗", he.getMessage());
}
log.error("payPal 捕獲訂單異常: " + ioe);
return CommonResult.fail(500, "NetworkTimeout");
}
}
這裡捕獲失敗是因為我已經捕獲了訂單(一個訂單隻能捕獲一次), 在哪裡捕獲的請往下看, 支付成功回調
{
"code": 500,
"message": "PayPal支付捕獲失敗",
"data": "{\"name\":\"UNPROCESSABLE_ENTITY\",\"details\":[{\"issue\":\"ORDER_ALREADY_CAPTURED\",\"description\":\"Order already captured.If 'intent=CAPTURE' only one capture per order is allowed.\"}],\"message\":\"The requested action could not be performed, semantically incorrect, or failed business validation.\",\"debug_id\":\"8c7d935811111\",\"links\":[{\"href\":\"https://developer.paypal.com/docs/api/orders/v2/#error-ORDER_ALREADY_CAPTURED\",\"rel\":\"information_link\",\"method\":\"GET\"}]}"
}
4、查詢訂單
@Override
public CommonResult queryOrder(String token) {
PayPalHttpClient client;
// 設定環境沙盒或生産
if (true) {
client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
} else {
client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
}
OrdersGetRequest request = new OrdersGetRequest(token);
try {
HttpResponse<Order> response = client.execute(request);
Order order = response.result();
return CommonResult.success("SUCCESS", order.status());
} catch (IOException ioe) {
if (ioe instanceof HttpException) {
HttpException he = (HttpException) ioe;
log.error("payPal 查詢訂單異常: " + he.getMessage());
return CommonResult.failMessage(500, "PayPal支付查詢失敗", he.getMessage());
}
log.error("payPal 查詢訂單異常: " + ioe);
return CommonResult.fail(500, "NetworkTimeout");
}
}
狀态碼請參考最後
{
"code": 200,
"message": "SUCCESS",
"data": "COMPLETED"
}
5、申請退款
@Override
public CommonResult refundOrder(String token) {
PayPalHttpClient client;
// 設定環境沙盒或生産
if (true) {
client = new PayPalHttpClient(new PayPalEnvironment.Sandbox(clientId, secret));
} else {
client = new PayPalHttpClient(new PayPalEnvironment.Live(clientId, secret));
}
// 查詢支付訂單, 拿到退款訂單号
OrdersGetRequest ordersGetRequest = new OrdersGetRequest(token);
try {
HttpResponse<Order> orderResponse = client.execute(ordersGetRequest);
Order order = orderResponse.result();
String captureId = null;
for (PurchaseUnit purchaseUnit : order.purchaseUnits()) {
for (Capture capture : purchaseUnit.payments().captures()) {
captureId = capture.id();
}
}
if (captureId == null) {
return CommonResult.fail(500, "PayPal申請退款失敗");
}
// 申請退款
CapturesRefundRequest request = new CapturesRefundRequest(captureId);
HttpResponse<com.paypal.payments.Refund> response = client.execute(request);
com.paypal.payments.Refund refund = response.result();
if ("COMPLETED".equals(refund.status())) {
return CommonResult.success("SUCCESS", captureId);
}
return CommonResult.fail(500, "PayPal申請退款失敗");
} catch (IOException ioe) {
if (ioe instanceof HttpException) {
HttpException he = (HttpException) ioe;
log.error("payPal 申請退款異常: " + he.getMessage());
return CommonResult.failMessage(500, "PayPal支付查詢失敗", he.getMessage());
}
log.error("payPal申請退款異常: " + ioe);
return CommonResult.fail(500, "NetworkTimeout");
}
}
狀态碼請參考最後
{
"code": 200,
"message": "SUCCESS",
"data": "0LX49400YH7782525"
}
6、支付成功回調通知
@Override
public CommonResult paypalSuccess(HttpServletRequest request) {
// 通過 token 查詢到訂單記錄
String token = request.getParameter("token");
// 拿到訂單記錄對訂單進行捕獲操作
// 目前測試訂單沒有儲存起來, 就手動填寫進來
return captureOrder(token);
}
7、支付失敗回調通知
@Override
public CommonResult paypalFail(HttpServletRequest request) {
return CommonResult.fail(500, "FAIL");
}
8:雜談
1、前期有點繁瑣, 碰到問題不是太好找到解決方法, 後期感覺也還好
2、貨币機關這個很重要, 不然訂單不能自動結賬, 需要手動處理, 因為匯率問題
3、然後打開網頁的這個網速, 确實有點說不過去, 太慢了, 唉
4、代碼上傳碼雲位址:https://gitee.com/xmaxm/payments_hodgepodge