PayPalService.java 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package com.cyksj.service.paypal;
  2. import com.cyksj.common.exception.BusinessRuntimeException;
  3. import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
  4. import com.cyksj.common.util.Jsons;
  5. import com.cyksj.enums.GatewayApiCode;
  6. import com.cyksj.model.entity.OrderDon;
  7. import com.cyksj.model.entity.PaypalPayConfig;
  8. import com.cyksj.model.request.OrderRefundReq;
  9. import com.cyksj.redis.RedisService;
  10. import com.cyksj.service.order.OrderDonService;
  11. import com.paypal.api.payments.*;
  12. import com.paypal.api.payments.Currency;
  13. import com.paypal.base.rest.APIContext;
  14. import com.paypal.base.rest.OAuthTokenCredential;
  15. import com.paypal.base.rest.PayPalRESTException;
  16. import lombok.RequiredArgsConstructor;
  17. import lombok.extern.slf4j.Slf4j;
  18. import org.springframework.stereotype.Service;
  19. import java.io.InputStream;
  20. import java.io.OutputStreamWriter;
  21. import java.math.BigDecimal;
  22. import java.math.RoundingMode;
  23. import java.net.HttpURLConnection;
  24. import java.net.URL;
  25. import java.util.*;
  26. /**
  27. * @author chan
  28. * @date 2021/3/26 11:03 上午
  29. */
  30. @Service
  31. @Slf4j
  32. @RequiredArgsConstructor
  33. public class PayPalService{
  34. private static final GlobalThreadPoolTaskExecutor THREAD_POOL = GlobalThreadPoolTaskExecutor.getInstance();
  35. private final OrderDonService orderDonService;
  36. private final PaypalPayConfigService paypalPayConfigService;
  37. private final RedisService redisService;
  38. private static final String SANDBOX_URL = "https://api-m.sandbox.paypal.com";
  39. private static final String LIVE_URL = "https://api-m.paypal.com";
  40. public String successPayment(String paymentId, String payerId,PaypalPayConfig paypalPayConfig) throws Exception {
  41. Payment payment = null;
  42. try {
  43. payment = this.executePayment(paymentId,payerId,paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  44. } catch (PayPalRESTException e) {
  45. log.error("支付回调失败",e);
  46. return paypalPayConfig.getCancelUrl();
  47. }
  48. PayerInfo payerInfo = payment.getPayer().getPayerInfo();
  49. log.info("paypal 支付回调 用户信息:{}", payerInfo);
  50. //支付成功
  51. if("approved".equals(payment.getState())){
  52. //paypal 交易id
  53. Sale sale = payment.getTransactions().get(0).getRelatedResources().get(0).getSale();
  54. Currency transactionFee = sale.getTransactionFee();
  55. String transationId = sale.getId();
  56. String orderId = payment.getTransactions().get(0).getCustom();
  57. //更新订单支付状态
  58. OrderDon orderDon = orderDonService.getById(orderId);
  59. orderDon.setTransactionId(transationId);
  60. orderDon.setPayTime(new Date());
  61. orderDon.setAbroadTransactionFee(new BigDecimal(transactionFee.getValue()).multiply(BigDecimal.valueOf(100)));
  62. orderDonService.orderNotify(orderDon);
  63. log.info("支付成功订单:"+orderId+",支付交易号:"+transationId);
  64. log.info("支付成功订单:"+orderId+",返回参数:"+Jsons.toJson(payment));
  65. THREAD_POOL.execute(()->{
  66. try {
  67. APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
  68. URL url = new URL("live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL + "/v1/shipping/trackers-batch");
  69. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  70. httpConn.setRequestMethod("POST");
  71. httpConn.setRequestProperty("Content-Type", "application/json");
  72. httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
  73. httpConn.setDoOutput(true);
  74. OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
  75. writer.write("{\"trackers\": [{ \"transaction_id\": \"" + transationId + "\", \"status\": \"SHIPPED\"}]}");
  76. writer.flush();
  77. writer.close();
  78. httpConn.getOutputStream().close();
  79. InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
  80. Scanner s = new Scanner(responseStream).useDelimiter("\\A");
  81. String response = s.hasNext() ? s.next() : "";
  82. log.info("添加物流信息 response:{}",response);
  83. } catch (Exception e) {
  84. e.printStackTrace();
  85. }
  86. });
  87. return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
  88. }
  89. log.info("支付失败返回参数:"+ Jsons.toJson(payment));
  90. return paypalPayConfig.getCancelUrl();
  91. }
  92. public Payment createPayment(Long orderId,String successUrl) throws PayPalRESTException {
  93. redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
  94. OrderDon orderDon = orderDonService.getById(orderId);
  95. orderDon.setType(OrderDon.Type.PAYPAL);
  96. orderDonService.updateById(orderDon);
  97. if (OrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
  98. throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"The donation has been paid");
  99. }
  100. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  101. // Set payer details
  102. Payer payer = new Payer();
  103. payer.setPaymentMethod("paypal");
  104. // Set redirect URLs
  105. RedirectUrls redirectUrls = new RedirectUrls();
  106. redirectUrls.setCancelUrl(paypalPayConfig.getCancelUrl());
  107. String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applets/order/paypal/notify";
  108. //成功回调地址(自己写的/pay/success)
  109. redirectUrls.setReturnUrl(returnUrl);
  110. Transaction transaction = new Transaction();
  111. transaction.setDescription("");
  112. transaction.setCustom(orderDon.getId().toString());
  113. //订单价格
  114. Amount amount = new Amount();
  115. amount.setCurrency("USD");
  116. // 支付的总价,paypal会校验 total = subTotal + tax + ...
  117. BigDecimal totalMoney = orderDon.getMoney().divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
  118. amount.setTotal(totalMoney.toString());
  119. // 设置各种费用
  120. Details details = new Details();
  121. //商品总价
  122. details.setSubtotal(totalMoney.toString());
  123. amount.setDetails(details);
  124. transaction.setAmount(amount);
  125. // Add transaction to a list
  126. List<Transaction> transactions = new ArrayList<Transaction>();
  127. transactions.add(transaction);
  128. // Add payment details
  129. Payment payment = new Payment();
  130. payment.setIntent("sale");
  131. payment.setPayer(payer);
  132. payment.setRedirectUrls(redirectUrls);
  133. payment.setTransactions(transactions);
  134. return payment.create(this.getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()));
  135. }
  136. private APIContext getAPIContext(String clientId,String clientSecret,String mode) throws PayPalRESTException {
  137. Map<String, String> sdkConfig = new HashMap<>();
  138. sdkConfig.put("mode", mode);
  139. OAuthTokenCredential authTokenCredential = new OAuthTokenCredential(clientId,clientSecret,sdkConfig);
  140. APIContext apiContext = new APIContext(authTokenCredential.getAccessToken());
  141. apiContext.setConfigurationMap(sdkConfig);
  142. return apiContext;
  143. }
  144. /**
  145. * 执行支付
  146. */
  147. public Payment executePayment(String paymentId, String PayerID,String clientId,String clientSecret,String mode) throws PayPalRESTException {
  148. Payment payment = new Payment();
  149. payment.setId(paymentId);
  150. PaymentExecution paymentExecute = new PaymentExecution();
  151. paymentExecute.setPayerId(PayerID);
  152. return payment.execute(this.getAPIContext(clientId,clientSecret,mode), paymentExecute);
  153. }
  154. public void refund(OrderRefundReq refundReq, OrderDon orderDon) throws PayPalRESTException {
  155. BigDecimal net = refundReq.getRefundMoney().subtract(orderDon.getAbroadTransactionFee());
  156. log.info("paypal return order:{},money:{}",orderDon.getId(),net);
  157. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  158. APIContext apiContext = getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  159. Sale sale = Sale.get(apiContext, orderDon.getTransactionId());
  160. Refund refund = new Refund();
  161. refund.setAmount(new Amount(orderDon.getCurrency(), net.divide(new BigDecimal(100),2,RoundingMode.HALF_DOWN).toString()));
  162. refund = sale.refund(apiContext, refund);
  163. log.info("paypal return refund:{}",refund);
  164. if (!"completed".equals(refund.getState())) {
  165. throw BusinessRuntimeException.getInstance("退款失败,e:{0}", refund.getDescription());
  166. }
  167. }
  168. }