PayPalService.java 10.0 KB

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