PayPalService.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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.mapper.GoodsDonSkuMapper;
  7. import com.cyksj.model.entity.GoodsDonSku;
  8. import com.cyksj.model.entity.OrderDon;
  9. import com.cyksj.model.entity.PaypalPayConfig;
  10. import com.cyksj.model.entity.VipOrderDon;
  11. import com.cyksj.model.request.OrderRefundReq;
  12. import com.cyksj.redis.RedisService;
  13. import com.cyksj.service.order.OrderDonService;
  14. import com.cyksj.service.order.VipOrderDonService;
  15. import com.paypal.api.payments.Currency;
  16. import com.paypal.api.payments.*;
  17. import com.paypal.base.rest.APIContext;
  18. import com.paypal.base.rest.OAuthTokenCredential;
  19. import com.paypal.base.rest.PayPalRESTException;
  20. import lombok.RequiredArgsConstructor;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.springframework.stereotype.Service;
  23. import java.io.InputStream;
  24. import java.io.OutputStreamWriter;
  25. import java.math.BigDecimal;
  26. import java.math.RoundingMode;
  27. import java.net.HttpURLConnection;
  28. import java.net.URL;
  29. import java.util.*;
  30. /**
  31. * @author chan
  32. * @date 2021/3/26 11:03 上午
  33. */
  34. @Service
  35. @Slf4j
  36. @RequiredArgsConstructor
  37. public class PayPalService{
  38. private static final GlobalThreadPoolTaskExecutor THREAD_POOL = GlobalThreadPoolTaskExecutor.getInstance();
  39. private final OrderDonService orderDonService;
  40. private final PaypalPayConfigService paypalPayConfigService;
  41. private final RedisService redisService;
  42. private final GoodsDonSkuMapper skuMapper;
  43. private final VipOrderDonService vipOrderDonService;
  44. private static final String SANDBOX_URL = "https://api-m.sandbox.paypal.com";
  45. private static final String LIVE_URL = "https://api-m.paypal.com";
  46. public String successPayment(String paymentId, String payerId,PaypalPayConfig paypalPayConfig) throws Exception {
  47. log.info("paypal回调 paymentId:{},payerId:{}",paymentId,payerId);
  48. Payment payment = null;
  49. try {
  50. payment = this.executePayment(paymentId,payerId,paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  51. } catch (PayPalRESTException e) {
  52. log.error("支付回调失败",e);
  53. payment = Payment.get(getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()), paymentId);
  54. }
  55. PayerInfo payerInfo = payment.getPayer().getPayerInfo();
  56. log.info("paypal 支付回调 用户信息:{}", payerInfo);
  57. //支付成功
  58. if("approved".equals(payment.getState())){
  59. //paypal 交易id
  60. Sale sale = payment.getTransactions().get(0).getRelatedResources().get(0).getSale();
  61. log.info("paypal 支付回调 订单信息:{}", sale);
  62. Currency transactionFee = sale.getTransactionFee();
  63. String transationId = sale.getId();
  64. String orderId = payment.getTransactions().get(0).getCustom();
  65. //更新订单支付状态
  66. OrderDon orderDon = orderDonService.getById(orderId);
  67. orderDon.setTransactionId(transationId);
  68. orderDon.setPayTime(new Date());
  69. orderDon.setAbroadTransactionFee(new BigDecimal(transactionFee.getValue()).multiply(BigDecimal.valueOf(100)));
  70. orderDonService.orderNotify(orderDon);
  71. log.info("支付成功订单:"+orderId+",支付交易号:"+transationId);
  72. log.info("支付成功订单:"+orderId+",返回参数:"+payment);
  73. THREAD_POOL.execute(()->{
  74. try {
  75. APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
  76. String baseUrl = "live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL;
  77. URL url = new URL(baseUrl + "/v1/shipping/trackers-batch");
  78. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  79. httpConn.setRequestMethod("POST");
  80. httpConn.setRequestProperty("Content-Type", "application/json");
  81. httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
  82. httpConn.setDoOutput(true);
  83. OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
  84. writer.write("{\"trackers\": [{ \"transaction_id\": \"" + transationId + "\", \"status\": \"SHIPPED\"}]}");
  85. writer.flush();
  86. writer.close();
  87. httpConn.getOutputStream().close();
  88. InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
  89. Scanner s = new Scanner(responseStream).useDelimiter("\\A");
  90. String response = s.hasNext() ? s.next() : "";
  91. log.info("添加物流信息 response:{}",response);
  92. } catch (Exception e) {
  93. e.printStackTrace();
  94. }
  95. });
  96. return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
  97. }
  98. log.info("支付失败返回参数:"+ Jsons.toJson(payment));
  99. return paypalPayConfig.getCancelUrl();
  100. }
  101. public Payment createPayment(Long orderId,String successUrl) throws PayPalRESTException {
  102. OrderDon orderDon = orderDonService.getById(orderId);
  103. if (orderDon.getGoodsId() == 26) {
  104. GoodsDonSku sku = skuMapper.selectById(orderDon.getSkuId());
  105. if (!sku.getIsMirror()) {
  106. throw BusinessRuntimeException.getInstance("订单异常..");
  107. }
  108. }
  109. //paypal 不能购买奈飞月付账号 24-1-23
  110. if (orderDon.getSkuId() != null && orderDon.getSkuId() == 4) {
  111. throw BusinessRuntimeException.getInstance("暂不支持paypal购买该规格车票..");
  112. }
  113. redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
  114. BigDecimal money = orderDon.getMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN);
  115. orderDon.setAbroadMoney(money);
  116. orderDon.setType(OrderDon.Type.PAYPAL);
  117. orderDonService.updateById(orderDon);
  118. if (OrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
  119. throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"该订单已支付");
  120. }
  121. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  122. // Set payer details
  123. Payer payer = new Payer();
  124. payer.setPaymentMethod("paypal");
  125. // Set redirect URLs
  126. RedirectUrls redirectUrls = new RedirectUrls();
  127. redirectUrls.setCancelUrl(paypalPayConfig.getCancelUrl());
  128. String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applets/order/paypal/notify";
  129. //成功回调地址(自己写的/pay/success)
  130. redirectUrls.setReturnUrl(returnUrl);
  131. Transaction transaction = new Transaction();
  132. transaction.setDescription("");
  133. transaction.setCustom(orderDon.getId().toString());
  134. //订单价格
  135. Amount amount = new Amount();
  136. amount.setCurrency("USD");
  137. // 支付的总价,paypal会校验 total = subTotal + tax + ...
  138. BigDecimal totalMoney = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
  139. amount.setTotal(totalMoney.toString());
  140. // 设置各种费用
  141. Details details = new Details();
  142. //商品总价
  143. details.setSubtotal(totalMoney.toString());
  144. amount.setDetails(details);
  145. transaction.setAmount(amount);
  146. // Add transaction to a list
  147. List<Transaction> transactions = new ArrayList<Transaction>();
  148. transactions.add(transaction);
  149. // Add payment details
  150. Payment payment = new Payment();
  151. payment.setIntent("sale");
  152. payment.setPayer(payer);
  153. payment.setRedirectUrls(redirectUrls);
  154. payment.setTransactions(transactions);
  155. return payment.create(this.getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()));
  156. }
  157. private APIContext getAPIContext(String clientId,String clientSecret,String mode) throws PayPalRESTException {
  158. Map<String, String> sdkConfig = new HashMap<>();
  159. sdkConfig.put("mode", mode);
  160. OAuthTokenCredential authTokenCredential = new OAuthTokenCredential(clientId,clientSecret,sdkConfig);
  161. APIContext apiContext = new APIContext(authTokenCredential.getAccessToken());
  162. apiContext.setConfigurationMap(sdkConfig);
  163. return apiContext;
  164. }
  165. /**
  166. * 执行支付
  167. */
  168. public Payment executePayment(String paymentId, String PayerID,String clientId,String clientSecret,String mode) throws PayPalRESTException {
  169. Payment payment = new Payment();
  170. payment.setId(paymentId);
  171. PaymentExecution paymentExecute = new PaymentExecution();
  172. paymentExecute.setPayerId(PayerID);
  173. return payment.execute(this.getAPIContext(clientId,clientSecret,mode), paymentExecute);
  174. }
  175. public Boolean refund(OrderRefundReq refundReq, OrderDon orderDon) throws PayPalRESTException {
  176. BigDecimal net = refundReq.getRefundMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN).subtract(orderDon.getAbroadTransactionFee());;
  177. log.info("paypal return order:{},money:{}",orderDon.getId(),net);
  178. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  179. APIContext apiContext = getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
  180. Sale sale = Sale.get(apiContext, orderDon.getTransactionId());
  181. Refund refund = new Refund();
  182. refund.setAmount(new Amount("USD", net.divide(new BigDecimal(100),2,RoundingMode.HALF_DOWN).toString()));
  183. refund = sale.refund(apiContext, refund);
  184. log.info("paypal return refund:{}",refund);
  185. if ("completed".equals(refund.getState())){
  186. orderDon.setStatus(OrderDon.Status.refund);
  187. orderDonService.updateById(orderDon);
  188. return true;
  189. }
  190. return false;
  191. }
  192. public Payment createVipPayment(Long orderId, String successUrl) throws PayPalRESTException {
  193. VipOrderDon orderDon = vipOrderDonService.getById(orderId);
  194. redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
  195. BigDecimal money = orderDon.getMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN);
  196. orderDon.setAbroadMoney(money);
  197. orderDon.setType(VipOrderDon.Type.PAYPAL);
  198. vipOrderDonService.updateById(orderDon);
  199. if (VipOrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
  200. throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"该订单已支付");
  201. }
  202. PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
  203. // Set payer details
  204. Payer payer = new Payer();
  205. payer.setPaymentMethod("paypal");
  206. // Set redirect URLs
  207. RedirectUrls redirectUrls = new RedirectUrls();
  208. redirectUrls.setCancelUrl(paypalPayConfig.getCancelUrl());
  209. String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applet/vip/orders/paypal/notify";
  210. //成功回调地址(自己写的/pay/success)
  211. redirectUrls.setReturnUrl(returnUrl);
  212. Transaction transaction = new Transaction();
  213. transaction.setDescription("");
  214. transaction.setCustom(orderDon.getId().toString());
  215. //订单价格
  216. Amount amount = new Amount();
  217. amount.setCurrency("USD");
  218. // 支付的总价,paypal会校验 total = subTotal + tax + ...
  219. BigDecimal totalMoney = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
  220. amount.setTotal(totalMoney.toString());
  221. // 设置各种费用
  222. Details details = new Details();
  223. //商品总价
  224. details.setSubtotal(totalMoney.toString());
  225. amount.setDetails(details);
  226. transaction.setAmount(amount);
  227. // Add transaction to a list
  228. List<Transaction> transactions = new ArrayList<Transaction>();
  229. transactions.add(transaction);
  230. // Add payment details
  231. Payment payment = new Payment();
  232. payment.setIntent("sale");
  233. payment.setPayer(payer);
  234. payment.setRedirectUrls(redirectUrls);
  235. payment.setTransactions(transactions);
  236. return payment.create(this.getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()));
  237. }
  238. public String successVipPayment(String paymentId, String payerId, PaypalPayConfig paypalPayConfig) throws Exception {
  239. log.info("paypal回调 paymentId:{},payerId:{}", paymentId, payerId);
  240. Payment payment = null;
  241. try {
  242. payment = this.executePayment(paymentId, payerId, paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
  243. } catch (PayPalRESTException e) {
  244. log.error("支付回调失败", e);
  245. payment = Payment.get(getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode()), paymentId);
  246. }
  247. PayerInfo payerInfo = payment.getPayer().getPayerInfo();
  248. log.info("paypal 支付回调 用户信息:{}", payerInfo);
  249. //支付成功
  250. if ("approved".equals(payment.getState())) {
  251. //paypal 交易id
  252. Sale sale = payment.getTransactions().get(0).getRelatedResources().get(0).getSale();
  253. log.info("paypal 支付回调 订单信息:{}", sale);
  254. Currency transactionFee = sale.getTransactionFee();
  255. String transationId = sale.getId();
  256. String orderId = payment.getTransactions().get(0).getCustom();
  257. //更新订单支付状态
  258. VipOrderDon orderDon = vipOrderDonService.getById(orderId);
  259. orderDon.setTransactionId(transationId);
  260. orderDon.setPayTime(new Date());
  261. orderDon.setAbroadTransactionFee(new BigDecimal(transactionFee.getValue()).multiply(BigDecimal.valueOf(100)));
  262. vipOrderDonService.orderNotify(orderDon);
  263. log.info("支付成功订单:" + orderId + ",支付交易号:" + transationId);
  264. log.info("支付成功订单:" + orderId + ",返回参数:" + payment);
  265. THREAD_POOL.execute(() -> {
  266. try {
  267. APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
  268. String baseUrl = "live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL;
  269. URL url = new URL(baseUrl + "/v1/shipping/trackers-batch");
  270. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  271. httpConn.setRequestMethod("POST");
  272. httpConn.setRequestProperty("Content-Type", "application/json");
  273. httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
  274. httpConn.setDoOutput(true);
  275. OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
  276. writer.write("{\"trackers\": [{ \"transaction_id\": \"" + transationId + "\", \"status\": \"SHIPPED\"}]}");
  277. writer.flush();
  278. writer.close();
  279. httpConn.getOutputStream().close();
  280. InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
  281. Scanner s = new Scanner(responseStream).useDelimiter("\\A");
  282. String response = s.hasNext() ? s.next() : "";
  283. log.info("添加物流信息 response:{}", response);
  284. } catch (Exception e) {
  285. e.printStackTrace();
  286. }
  287. });
  288. return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
  289. }
  290. log.info("支付失败返回参数:" + Jsons.toJson(payment));
  291. return paypalPayConfig.getCancelUrl();
  292. }
  293. }