PaypalService.java 18 KB

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