PayPalService.java 9.8 KB

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