PaypalService.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. package com.fdkankan.pay.util.paypal.sdk;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.fdkankan.pay.common.ResultCode;
  5. import com.fdkankan.pay.entity.AliConfig;
  6. import com.fdkankan.pay.entity.AutopayOrder;
  7. import com.fdkankan.pay.entity.Order;
  8. import com.fdkankan.pay.entity.PaypalConfig;
  9. import com.fdkankan.pay.exception.BusinessException;
  10. import com.fdkankan.pay.response.OpenPayResponse;
  11. import com.fdkankan.pay.service.IAutopayOrderService;
  12. import com.fdkankan.pay.service.IOrderService;
  13. import com.fdkankan.pay.service.IPaypalConfigService;
  14. import com.fdkankan.pay.util.CacheUtil;
  15. import com.fdkankan.pay.util.UrlUtils;
  16. import com.fdkankan.pay.util.paypal.restApi.RestApiPaypalService;
  17. import com.fdkankan.pay.util.paypal.restApi.vo.Product;
  18. import com.fdkankan.pay.util.paypal.restApi.vo.plan.PlanVo;
  19. import com.fdkankan.pay.util.paypal.restApi.vo.subscription.ApplicationContext;
  20. import com.fdkankan.pay.util.paypal.restApi.vo.subscription.PaymentMethod;
  21. import com.fdkankan.pay.util.paypal.restApi.vo.subscription.SubscriptionVo;
  22. import com.paypal.api.payments.*;
  23. import com.paypal.base.codec.binary.Base64;
  24. import com.paypal.base.rest.APIContext;
  25. import com.paypal.base.rest.PayPalRESTException;
  26. import lombok.extern.log4j.Log4j2;
  27. import org.apache.commons.lang.StringUtils;
  28. import org.springframework.beans.factory.annotation.Autowired;
  29. import org.springframework.stereotype.Service;
  30. import org.springframework.transaction.annotation.Transactional;
  31. import javax.servlet.http.HttpServletRequest;
  32. import javax.servlet.http.HttpServletResponse;
  33. import java.io.*;
  34. import java.math.BigDecimal;
  35. import java.net.HttpURLConnection;
  36. import java.net.URL;
  37. import java.net.URLEncoder;
  38. import java.util.*;
  39. @Log4j2
  40. @Service
  41. public class PaypalService {
  42. @Autowired
  43. IPaypalConfigService paypalConfigService;
  44. @Autowired
  45. IOrderService orderService;
  46. public Object openPay(Order param, String ip) throws Exception {
  47. String orderSn = param.getOrderSn();
  48. BigDecimal amount = param.getOrderMoney();
  49. String subject = param.getOrderType();
  50. PaypalConfig paypalConfig = paypalConfigService.getByServeId(param.getServeId());
  51. if(paypalConfig == null){
  52. throw new BusinessException(ResultCode.PAYPAL_CONFIG_ERROR);
  53. }
  54. paypalConfig.setSuccessUrl( CacheUtil.mainUrl + paypalConfig.getCallBackUrl() +"/"+orderSn+"/"+param.getPayType()+"/success");
  55. paypalConfig.setCancelUrl( CacheUtil.mainUrl + paypalConfig.getCallBackUrl() +"/"+orderSn+"/"+param.getPayType()+"/cancel");
  56. String body = subject;
  57. //paypal支付,未开启自动订阅
  58. if(param.getPayType() == 5 && param.getAutoPay() == 0){
  59. return this.payPalPay(orderSn, body, amount,paypalConfig);
  60. }
  61. //paypal支付,开启自动订阅
  62. if(param.getPayType() == 5 && param.getAutoPay() == 1){
  63. return this.autoPay(param,paypalConfig);
  64. }
  65. throw new BusinessException(ResultCode.WX_ORDER_PAY_TYPE_ERROR);
  66. }
  67. public OpenPayResponse payPalPay(String orderSn, String body, BigDecimal totalFee, PaypalConfig paypalConfig) throws Exception {
  68. PayPalmentEx payPalmentEx = new PayPalmentEx();
  69. payPalmentEx.setOrderSn(orderSn);
  70. payPalmentEx.setOrderTotal(totalFee);
  71. payPalmentEx.setSubTotal(totalFee);
  72. payPalmentEx.setDescription(body);
  73. Payment payment = this.createPayment(payPalmentEx,paypalConfig);
  74. for(Links links : payment.getLinks()){
  75. if(links.getRel().equals("approval_url")){
  76. // 客户付款登陆地址
  77. OpenPayResponse openPayResponse = new OpenPayResponse();
  78. openPayResponse.setH5Url(links.getHref());
  79. openPayResponse.setQrCodeUrl(links.getHref());
  80. openPayResponse.setOrderSn(orderSn);
  81. openPayResponse.setPayType(5);
  82. return openPayResponse;
  83. }
  84. }
  85. throw new BusinessException(ResultCode.PAYPAL_ERROR);
  86. }
  87. public Boolean callBack(HttpServletRequest request, HttpServletResponse response, Order order,String result) {
  88. log.info("paypal-callBack--order:{}",order);
  89. Boolean payFlag = false;
  90. String trade_no = null;
  91. String openId = null;
  92. if("cancel".equals(result)){
  93. return false;
  94. }
  95. try {
  96. String paymentId = request.getParameter("paymentId");//商品名
  97. String payerId = request.getParameter("PayerID");//购买数量
  98. PaypalConfig paypalConfig = paypalConfigService.getByServeId(order.getServeId());
  99. if(paypalConfig == null){
  100. log.error("paypal-callBack--paypalConfig-notexist");
  101. return false;
  102. }
  103. log.info("paypal回调参数:paymentId:{},payerId:{}", paymentId,payerId);
  104. Payment payment = this.executePayment(paymentId, payerId,paypalConfig);
  105. if (payment.getState().equals("approved")) {
  106. log.info("paypal支付成功回调");
  107. String custom = payment.getTransactions().get(0).getCustom();
  108. String txnId = payment.getTransactions().get(0).getRelatedResources().get(0).getSale().getId();
  109. String payerEmail = payment.getTransactions().get(0).getPayee().getEmail();
  110. log.info("paypal-callBack:custom:{},txnid:{},payerEmail:{}",custom,txnId,payerEmail);
  111. String orderSn = custom.split("_")[0];
  112. if(custom.split("_").length > 2 && custom.split("_")[2].matches("^-?[0-9]+")){
  113. orderSn += "_" + custom.split("_")[2];
  114. }
  115. payFlag = true;
  116. trade_no = txnId;
  117. openId = payerEmail;
  118. }
  119. }catch (Exception e) {
  120. log.error("paypal支付回调异常,errorMsg:{}", e.getMessage());
  121. return false;
  122. }finally {
  123. orderService.payResult(order,payFlag,trade_no,openId);
  124. }
  125. return true;
  126. }
  127. // public Boolean callBack(HttpServletRequest request, HttpServletResponse response, Order order) {
  128. // log.info("paypal-callBack--order:{}",order);
  129. // Boolean payFlag = false;
  130. // String trade_no = null;
  131. // String openId = null;
  132. // try {
  133. // Enumeration en = request.getParameterNames();
  134. // String str = "cmd=_notify-validate";
  135. // while (en.hasMoreElements()) {
  136. // String paramName = (String) en.nextElement();
  137. // String paramValue = request.getParameter(paramName);
  138. // try {
  139. // str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue, "utf-8");
  140. // } catch (UnsupportedEncodingException e) {
  141. // StringWriter trace=new StringWriter();
  142. // e.printStackTrace(new PrintWriter(trace));
  143. // log.error(trace.toString());
  144. // }
  145. // //此处的编码一定要和自己的网站编码一致,不然会出现乱码,paypal回复的通知为‘INVALID’
  146. // }
  147. // final String itemName = request.getParameter("item_name");//商品名
  148. // final String itemNumber = request.getParameter("item_number");//购买数量
  149. // final String paymentDate = request.getParameter("payment_date");//交易时间
  150. // final String receiverEmail = request.getParameter("receiver_email");//收款人email
  151. // final String payerEmail = request.getParameter("payer_email");//付款人email
  152. // final String paymentAmount = request.getParameter("mc_gross");//交易钱数
  153. // final String paymentCurrency = request.getParameter("mc_currency");//货币种类
  154. // final String paymentStatus = request.getParameter("payment_status");//交易状态
  155. // final String txnId = request.getParameter("txn_id");//交易id
  156. // String custom = request.getParameter("custom");//发送payment请求时候自定义的业务服务器订单号
  157. // log.info("paypal回调参数:itemName:{},itemNumber:{},paymentDate:{},receiverEmail:{}," +
  158. // "payerEmail:{},paymentAmount:{},paymentCurrency:{},paymentStatus:{},txnId:{},custom:{}",
  159. // itemName,itemNumber,paymentDate,receiverEmail,payerEmail,paymentAmount,paymentCurrency,paymentStatus,txnId,custom);
  160. //
  161. // trade_no = txnId;
  162. // openId = payerEmail;
  163. // if ("Completed".equals(paymentStatus)) {
  164. // //根据自己业务进行处理(修改订单状态,支付时间等等操作)
  165. // log.info("paypal支付成功回调");
  166. // //表示续费,有消费记录id
  167. // payFlag = true;
  168. // }
  169. // }catch (Exception e) {
  170. // log.error("paypal支付回调异常,errorMsg:{}", e.getMessage());
  171. // return false;
  172. // }finally {
  173. // orderService.payResult(order,payFlag,trade_no,openId);
  174. // }
  175. // return true;
  176. // }
  177. /**
  178. * 创建支付
  179. *
  180. * @param paymentEx
  181. * @return
  182. * @throws PayPalRESTException
  183. */
  184. @Transactional(rollbackFor = Exception.class)
  185. public Payment createPayment(PayPalmentEx paymentEx, PaypalConfig paypalConfig) throws PayPalRESTException {
  186. Transaction transaction = new Transaction();
  187. transaction.setDescription(paymentEx.getDescription());
  188. // 将我们的订单ID保存到支付信息中,用于后面支付回传
  189. if (null != paymentEx.getOrderSn()) {
  190. transaction.setCustom(paymentEx.getOrderSn());
  191. }
  192. //订单价格
  193. Amount amount = new Amount();
  194. amount.setCurrency(paypalConfig.getCurrency());
  195. // 支付的总价,paypal会校验 total = subTotal + tax + ...
  196. amount.setTotal(paymentEx.getOrderTotal().toString());
  197. // 设置各种费用
  198. Details details = new Details();
  199. // 商品总价
  200. if (paymentEx.getSubTotal() != null) {
  201. details.setSubtotal(paymentEx.getSubTotal().toString());
  202. }
  203. // 税费
  204. if (paymentEx.getTax() != null) {
  205. details.setTax(paymentEx.getTax().toString());
  206. }
  207. amount.setDetails(details);
  208. transaction.setAmount(amount);
  209. ItemList itemList = new ItemList();
  210. // 收货地址
  211. PaypalOrderAddressEx orderAddress = paymentEx.getPaypayOrderAddressEx();
  212. if (orderAddress != null) {
  213. ShippingAddress shippingAddress = new ShippingAddress();
  214. if (StringUtils.isNotEmpty(orderAddress.getFirstName()) && StringUtils.isNotEmpty(orderAddress.getLastName())) {
  215. shippingAddress.setRecipientName(orderAddress.getFirstName() + "." + orderAddress.getLastName());
  216. }
  217. shippingAddress.setCountryCode(orderAddress.getCountryCode());
  218. shippingAddress.setState(orderAddress.getState());
  219. shippingAddress.setCity(orderAddress.getCity());
  220. shippingAddress.setLine1(orderAddress.getAddress());
  221. shippingAddress.setPhone(orderAddress.getPhone());
  222. shippingAddress.setPostalCode(orderAddress.getPostalCode());
  223. itemList.setShippingAddress(shippingAddress);
  224. itemList.setShippingPhoneNumber(orderAddress.getPhone());
  225. }
  226. // 商品明细
  227. List<PaypalOrderItemEx> orderItemList = paymentEx.getPaypalOrderItemExList();
  228. if (orderItemList != null && orderItemList.size() > 0) {
  229. List<Item> items = new ArrayList<>();
  230. for (PaypalOrderItemEx orderItemEx : orderItemList) {
  231. Item item = new Item();
  232. item.setSku(orderItemEx.getSku());
  233. item.setName(orderItemEx.getName());
  234. item.setPrice(orderItemEx.getPrice().toString());
  235. item.setQuantity(String.valueOf(orderItemEx.getQuantity()));
  236. item.setCurrency(paypalConfig.getCurrency());
  237. items.add(item);
  238. }
  239. itemList.setItems(items);
  240. transaction.setItemList(itemList);
  241. }
  242. List<Transaction> transactions = new ArrayList<>();
  243. transactions.add(transaction);
  244. // 支付信息
  245. Payer payer = new Payer();
  246. payer.setPaymentMethod(PaypalPaymentMethod.paypal.toString());
  247. Payment payment = new Payment();
  248. //刷新accessToken时间;
  249. APIContext apiContext = new APIContext("Bearer " + getAccessToken(paypalConfig));
  250. Map<String, String> sdkConfig = new HashMap<>();
  251. sdkConfig.put("mode", paypalConfig.getMode());
  252. apiContext.setConfigurationMap(sdkConfig);
  253. payment.setIntent(PaypalPaymentIntent.sale.toString());
  254. payment.setPayer(payer);
  255. payment.setTransactions(transactions);
  256. //回调地址
  257. RedirectUrls redirectUrls = new RedirectUrls();
  258. redirectUrls.setReturnUrl(paypalConfig.getSuccessUrl());
  259. redirectUrls.setCancelUrl(paypalConfig.getCancelUrl());
  260. payment.setRedirectUrls(redirectUrls);
  261. return payment.create(apiContext);
  262. }
  263. /**
  264. * 执行支付
  265. *
  266. * @param paymentId
  267. * @param payerId
  268. * @return
  269. * @throws PayPalRESTException
  270. */
  271. public Payment executePayment(String paymentId, String payerId,PaypalConfig paypalConfig) throws PayPalRESTException {
  272. Payment payment = new Payment();
  273. payment.setId(paymentId);
  274. PaymentExecution paymentExecute = new PaymentExecution();
  275. paymentExecute.setPayerId(payerId);
  276. APIContext apiContext = new APIContext("Bearer " + getAccessToken(paypalConfig));
  277. Map<String, String> sdkConfig = new HashMap<>();
  278. sdkConfig.put("mode", paypalConfig.getMode());
  279. apiContext.setConfigurationMap(sdkConfig);
  280. return payment.execute(apiContext, paymentExecute);
  281. }
  282. /**
  283.      * 获取token
  284.      * 了解更多:https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
  285.      * @return
  286.      */
  287. private String getAccessToken(PaypalConfig paypalConfig) {
  288. BufferedReader reader = null;
  289. try {
  290. URL url = new URL(UrlUtils.TOKEN_URL);
  291. String authorization = paypalConfig.getClientId() + ":" + paypalConfig.getSecret();
  292. authorization = Base64.encodeBase64String(authorization.getBytes());
  293. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  294. conn.setRequestMethod("POST");// 提交模式
  295. //设置请求头header
  296. conn.setRequestProperty("Accept", "application/json");
  297. conn.setRequestProperty("Accept-Language", "en_US");
  298. conn.setRequestProperty("Authorization", "Basic " + authorization);
  299. // conn.setConnectTimeout(10000);//连接超时 单位毫秒
  300. // conn.setReadTimeout(2000);//读取超时 单位毫秒
  301. conn.setDoOutput(true);// 是否输入参数
  302. String params = "grant_type=client_credentials";
  303. conn.getOutputStream().write(params.getBytes());// 输入参数
  304. InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
  305. reader = new BufferedReader(inStream);
  306. StringBuilder result = new StringBuilder();
  307. String lineTxt = null;
  308. while ((lineTxt = reader.readLine()) != null) {
  309. result.append(lineTxt);
  310. }
  311. reader.close();
  312. //log.info("getAccessToken:" + accessTokey);
  313. return JSONObject.parseObject(result.toString()).getString("access_token");
  314. } catch (Exception err) {
  315. err.printStackTrace();
  316. } finally {
  317. if (reader != null){
  318. try {
  319. reader.close();
  320. } catch (IOException e) {
  321. e.printStackTrace();
  322. }
  323. }
  324. }
  325. return null;
  326. }
  327. public String getPaymentDetails(String paymentId,PaypalConfig paypalConfig) {
  328. BufferedReader reader = null;
  329. try {
  330. URL url = new URL(UrlUtils.PAYMENT_DETAIL + paymentId);
  331. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  332. conn.setRequestMethod("GET");// 提交模式
  333. //设置请求头header
  334. conn.setRequestProperty("Accept", "application/json");
  335. conn.setRequestProperty("Authorization", "Bearer " + getAccessToken(paypalConfig));
  336. // conn.setConnectTimeout(10000);//连接超时 单位毫秒
  337. // conn.setReadTimeout(2000);//读取超时 单位毫秒
  338. InputStreamReader inStream = new InputStreamReader(conn.getInputStream());
  339. reader = new BufferedReader(inStream);
  340. StringBuilder result = new StringBuilder();
  341. String lineTxt = null;
  342. while ((lineTxt = reader.readLine()) != null) {
  343. result.append(lineTxt);
  344. }
  345. reader.close();
  346. return result.toString();
  347. } catch (Exception err) {
  348. err.printStackTrace();
  349. }finally {
  350. if (reader != null){
  351. try {
  352. reader.close();
  353. } catch (IOException e) {
  354. e.printStackTrace();
  355. }
  356. }
  357. }
  358. return null;
  359. }
  360. public boolean verifyPayment(String paymentId,PaypalConfig paypalConfig){
  361. //从PayPal获取付款详情
  362. String str = getPaymentDetails(paymentId,paypalConfig);
  363. JSONObject detail = JSONObject.parseObject(str);
  364. //校验订单是否完成
  365. if("approved".equals(detail.getString("state"))){
  366. JSONObject transactions = detail.getJSONArray("transactions").getJSONObject(0);
  367. JSONObject amount = transactions.getJSONObject("amount");
  368. JSONArray relatedResources = transactions.getJSONArray("related_resources");
  369. //从数据库查询总金额与Paypal校验支付总金额
  370. double total = 0;
  371. if( total != amount.getDouble("total") ){
  372. return false;
  373. }
  374. //校验交易货币类型
  375. String currency = "USD";
  376. if( !currency.equals(amount.getString("currency")) ){
  377. return false;
  378. }
  379. //校验每个子订单是否完成
  380. for (int i = 0,j = relatedResources.size(); i < j; i++) {
  381. JSONObject sale = relatedResources.getJSONObject(i).getJSONObject("sale");
  382. if( !"completed".equals(sale.getString("state")) ){
  383. System.out.println("子订单未完成,订单状态:"+sale.getString("state"));
  384. }
  385. }
  386. return true;
  387. }
  388. return false;
  389. }
  390. @Autowired
  391. RestApiPaypalService restApiPaypalService;
  392. @Autowired
  393. IAutopayOrderService autopayOrderService;
  394. public Object autoPay(Order order, PaypalConfig paypalConfig) {
  395. AutopayOrder autopayOrder = autopayOrderService.getByOrderSn(order.getOrderSn());
  396. OpenPayResponse openPayResponse = new OpenPayResponse();
  397. openPayResponse.setOrderSn(order.getOrderSn());
  398. openPayResponse.setPayType(5);
  399. openPayResponse.setAutoPay(1);
  400. if(autopayOrder !=null){
  401. openPayResponse.setH5Url(autopayOrder.getSubscriptionHref());
  402. openPayResponse.setQrCodeUrl(autopayOrder.getSubscriptionHref());
  403. return openPayResponse;
  404. }
  405. autopayOrder = new AutopayOrder();
  406. Product product = new Product();
  407. product.setName(order.getOrderType());
  408. product.setDescription(order.getGoodsInfo().toJSONString());
  409. product.setType("SERVICE");
  410. String productId = restApiPaypalService.createProduct(paypalConfig, product);
  411. log.info("创建商品:"+productId);
  412. PlanVo plan = new PlanVo();
  413. plan.setProductId(productId);
  414. plan.setPlanName(order.getOrderType());
  415. plan.setTimeUnit(order.getAutoPayTime());
  416. plan.setCurrencyCode("USD");
  417. plan.setPrice(order.getOrderMoney().toString());
  418. String planId = restApiPaypalService.createPlan(paypalConfig, plan);
  419. log.info("创建订阅计划:"+planId);
  420. autopayOrder.setPlanId(planId);
  421. autopayOrder.setOrderSn(order.getOrderSn());
  422. autopayOrder.setProductId(productId);
  423. SubscriptionVo subscription = restApiPaypalService.createSubscription(paypalConfig, autopayOrder.getSubscriptionId());
  424. log.info("创建订阅支付链接:"+subscription);
  425. autopayOrder.setSubscriptionId(subscription.getSubscriptionId());
  426. autopayOrder.setSubscriptionHref(subscription.getSubscriptionHref());
  427. autopayOrderService.saveOrUpdate(autopayOrder);
  428. openPayResponse.setH5Url(subscription.getSubscriptionHref());
  429. openPayResponse.setQrCodeUrl(subscription.getSubscriptionHref());
  430. return openPayResponse;
  431. }
  432. }