PayPalService.java 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. log.info("paypal回调 paymentId:{},payerId:{}",paymentId,payerId);
  42. Payment payment = null;
  43. try {
  44. payment = this.executePayment(paymentId,payerId,paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  45. } catch (PayPalRESTException e) {
  46. log.error("支付回调失败",e);
  47. payment = Payment.get(getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()), paymentId);
  48. }
  49. PayerInfo payerInfo = payment.getPayer().getPayerInfo();
  50. log.info("paypal 支付回调 用户信息:{}", payerInfo);
  51. //支付成功
  52. if("approved".equals(payment.getState())){
  53. //paypal 交易id
  54. Sale sale = payment.getTransactions().get(0).getRelatedResources().get(0).getSale();
  55. log.info("paypal 支付回调 订单信息:{}", sale);
  56. Currency transactionFee = sale.getTransactionFee();
  57. String transationId = sale.getId();
  58. String orderId = payment.getTransactions().get(0).getCustom();
  59. //更新订单支付状态
  60. OrderDon orderDon = orderDonService.getById(orderId);
  61. orderDon.setTransactionId(transationId);
  62. orderDon.setPayTime(new Date());
  63. orderDon.setAbroadTransactionFee(new BigDecimal(transactionFee.getValue()).multiply(BigDecimal.valueOf(100)));
  64. orderDonService.orderNotify(orderDon);
  65. log.info("支付成功订单:"+orderId+",支付交易号:"+transationId);
  66. log.info("支付成功订单:"+orderId+",返回参数:"+Jsons.toJson(payment));
  67. THREAD_POOL.execute(()->{
  68. try {
  69. APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
  70. URL url = new URL("live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL + "/v1/shipping/trackers-batch");
  71. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  72. httpConn.setRequestMethod("POST");
  73. httpConn.setRequestProperty("Content-Type", "application/json");
  74. httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
  75. httpConn.setDoOutput(true);
  76. OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
  77. writer.write("{\"trackers\": [{ \"transaction_id\": \"" + transationId + "\", \"status\": \"SHIPPED\"}]}");
  78. writer.flush();
  79. writer.close();
  80. httpConn.getOutputStream().close();
  81. InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
  82. Scanner s = new Scanner(responseStream).useDelimiter("\\A");
  83. String response = s.hasNext() ? s.next() : "";
  84. log.info("添加物流信息 response:{}",response);
  85. } catch (Exception e) {
  86. e.printStackTrace();
  87. }
  88. });
  89. return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
  90. }
  91. log.info("支付失败返回参数:"+ Jsons.toJson(payment));
  92. return paypalPayConfig.getCancelUrl();
  93. }
  94. public Payment createPayment(Long orderId,String successUrl) throws PayPalRESTException {
  95. OrderDon orderDon = orderDonService.getById(orderId);
  96. //paypal 不能购买奈飞月付账号 24-1-23
  97. if (orderDon.getSkuId() != null && orderDon.getSkuId() == 4) {
  98. throw BusinessRuntimeException.getInstance("暂不支持paypal购买该规格车票..");
  99. }
  100. redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
  101. BigDecimal money = orderDon.getMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN);
  102. orderDon.setAbroadMoney(money);
  103. orderDon.setType(OrderDon.Type.PAYPAL);
  104. orderDonService.updateById(orderDon);
  105. if (OrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
  106. throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"该捐款已支付");
  107. }
  108. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  109. // Set payer details
  110. Payer payer = new Payer();
  111. payer.setPaymentMethod("paypal");
  112. // Set redirect URLs
  113. RedirectUrls redirectUrls = new RedirectUrls();
  114. redirectUrls.setCancelUrl(paypalPayConfig.getCancelUrl());
  115. String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applets/order/paypal/notify";
  116. //成功回调地址(自己写的/pay/success)
  117. redirectUrls.setReturnUrl(returnUrl);
  118. Transaction transaction = new Transaction();
  119. transaction.setDescription("");
  120. transaction.setCustom(orderDon.getId().toString());
  121. //订单价格
  122. Amount amount = new Amount();
  123. amount.setCurrency("USD");
  124. // 支付的总价,paypal会校验 total = subTotal + tax + ...
  125. BigDecimal totalMoney = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
  126. amount.setTotal(totalMoney.toString());
  127. // 设置各种费用
  128. Details details = new Details();
  129. //商品总价
  130. details.setSubtotal(totalMoney.toString());
  131. amount.setDetails(details);
  132. transaction.setAmount(amount);
  133. // Add transaction to a list
  134. List<Transaction> transactions = new ArrayList<Transaction>();
  135. transactions.add(transaction);
  136. // Add payment details
  137. Payment payment = new Payment();
  138. payment.setIntent("sale");
  139. payment.setPayer(payer);
  140. payment.setRedirectUrls(redirectUrls);
  141. payment.setTransactions(transactions);
  142. return payment.create(this.getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()));
  143. }
  144. private APIContext getAPIContext(String clientId,String clientSecret,String mode) throws PayPalRESTException {
  145. Map<String, String> sdkConfig = new HashMap<>();
  146. sdkConfig.put("mode", mode);
  147. OAuthTokenCredential authTokenCredential = new OAuthTokenCredential(clientId,clientSecret,sdkConfig);
  148. APIContext apiContext = new APIContext(authTokenCredential.getAccessToken());
  149. apiContext.setConfigurationMap(sdkConfig);
  150. return apiContext;
  151. }
  152. /**
  153. * 执行支付
  154. */
  155. public Payment executePayment(String paymentId, String PayerID,String clientId,String clientSecret,String mode) throws PayPalRESTException {
  156. Payment payment = new Payment();
  157. payment.setId(paymentId);
  158. PaymentExecution paymentExecute = new PaymentExecution();
  159. paymentExecute.setPayerId(PayerID);
  160. return payment.execute(this.getAPIContext(clientId,clientSecret,mode), paymentExecute);
  161. }
  162. public Boolean refund(OrderRefundReq refundReq, OrderDon orderDon) throws PayPalRESTException {
  163. BigDecimal net = refundReq.getRefundMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN).subtract(orderDon.getAbroadTransactionFee());;
  164. log.info("paypal return order:{},money:{}",orderDon.getId(),net);
  165. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  166. APIContext apiContext = getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  167. Sale sale = Sale.get(apiContext, orderDon.getTransactionId());
  168. Refund refund = new Refund();
  169. refund.setAmount(new Amount("USD", net.divide(new BigDecimal(100),2,RoundingMode.HALF_DOWN).toString()));
  170. refund = sale.refund(apiContext, refund);
  171. log.info("paypal return refund:{}",refund);
  172. if ("completed".equals(refund.getState())){
  173. orderDon.setStatus(OrderDon.Status.refund);
  174. orderDonService.updateById(orderDon);
  175. return true;
  176. }
  177. return false;
  178. }
  179. }