package com.fdkankan.pay.util.paypal.sdk; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.fdkankan.pay.common.ResultCode; import com.fdkankan.pay.entity.AliConfig; import com.fdkankan.pay.entity.Order; import com.fdkankan.pay.entity.PaypalConfig; import com.fdkankan.pay.exception.BusinessException; import com.fdkankan.pay.response.OpenPayResponse; import com.fdkankan.pay.service.IOrderService; import com.fdkankan.pay.service.IPaypalConfigService; import com.fdkankan.pay.util.CacheUtil; import com.fdkankan.pay.util.UrlUtils; import com.paypal.api.payments.*; import com.paypal.base.codec.binary.Base64; import com.paypal.base.rest.APIContext; import com.paypal.base.rest.PayPalRESTException; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.math.BigDecimal; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.*; @Log4j2 @Service public class PaypalService { @Autowired IPaypalConfigService paypalConfigService; @Autowired IOrderService orderService; public Object openPay(Order param, String ip) throws Exception { String orderSn = param.getOrderSn(); BigDecimal amount = param.getOrderMoney(); String subject = param.getOrderType(); PaypalConfig paypalConfig = paypalConfigService.getByServeId(param.getServeId()); if(paypalConfig == null){ throw new BusinessException(ResultCode.PAYPAL_CONFIG_ERROR); } paypalConfig.setSuccessUrl( CacheUtil.mainUrl + paypalConfig.getCallBackUrl() +"/"+orderSn+"/"+param.getPayType()+"/success"); paypalConfig.setCancelUrl( CacheUtil.mainUrl + paypalConfig.getCallBackUrl() +"/"+orderSn+"/"+param.getPayType()+"/cancel"); String body = subject; //paypal支付 if(param.getPayType() == 5){ return this.payPalPay(orderSn, body, amount,paypalConfig); } throw new BusinessException(ResultCode.WX_ORDER_PAY_TYPE_ERROR); } public OpenPayResponse payPalPay(String orderSn, String body, BigDecimal totalFee, PaypalConfig paypalConfig) throws Exception { PayPalmentEx payPalmentEx = new PayPalmentEx(); payPalmentEx.setOrderSn(orderSn); payPalmentEx.setOrderTotal(totalFee); payPalmentEx.setSubTotal(totalFee); payPalmentEx.setDescription(body); Payment payment = this.createPayment(payPalmentEx,paypalConfig); for(Links links : payment.getLinks()){ if(links.getRel().equals("approval_url")){ // 客户付款登陆地址 OpenPayResponse openPayResponse = new OpenPayResponse(); openPayResponse.setH5Url(links.getHref()); openPayResponse.setQrCodeUrl(links.getHref()); openPayResponse.setOrderSn(orderSn); openPayResponse.setPayType(5); return openPayResponse; } } throw new BusinessException(ResultCode.PAYPAL_ERROR); } public Boolean callBack(HttpServletRequest request, HttpServletResponse response, Order order,String result) { log.info("paypal-callBack--order:{}",order); Boolean payFlag = false; String trade_no = null; String openId = null; if("cancel".equals(result)){ return false; } try { String paymentId = request.getParameter("paymentId");//商品名 String payerId = request.getParameter("PayerID");//购买数量 PaypalConfig paypalConfig = paypalConfigService.getByServeId(order.getServeId()); if(paypalConfig == null){ log.error("paypal-callBack--paypalConfig-notexist"); return false; } log.info("paypal回调参数:paymentId:{},payerId:{}", paymentId,payerId); Payment payment = this.executePayment(paymentId, payerId,paypalConfig); if (payment.getState().equals("approved")) { log.info("paypal支付成功回调"); String custom = payment.getTransactions().get(0).getCustom(); String txnId = payment.getTransactions().get(0).getRelatedResources().get(0).getSale().getId(); String payerEmail = payment.getTransactions().get(0).getPayee().getEmail(); log.info("paypal-callBack:custom:{},txnid:{},payerEmail:{}",custom,txnId,payerEmail); String orderSn = custom.split("_")[0]; if(custom.split("_").length > 2 && custom.split("_")[2].matches("^-?[0-9]+")){ orderSn += "_" + custom.split("_")[2]; } payFlag = true; trade_no = txnId; openId = payerEmail; } }catch (Exception e) { log.error("paypal支付回调异常,errorMsg:{}", e.getMessage()); return false; }finally { orderService.payResult(order,payFlag,trade_no,openId); } return true; } // public Boolean callBack(HttpServletRequest request, HttpServletResponse response, Order order) { // log.info("paypal-callBack--order:{}",order); // Boolean payFlag = false; // String trade_no = null; // String openId = null; // try { // Enumeration en = request.getParameterNames(); // String str = "cmd=_notify-validate"; // while (en.hasMoreElements()) { // String paramName = (String) en.nextElement(); // String paramValue = request.getParameter(paramName); // try { // str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue, "utf-8"); // } catch (UnsupportedEncodingException e) { // StringWriter trace=new StringWriter(); // e.printStackTrace(new PrintWriter(trace)); // log.error(trace.toString()); // } // //此处的编码一定要和自己的网站编码一致,不然会出现乱码,paypal回复的通知为‘INVALID’ // } // final String itemName = request.getParameter("item_name");//商品名 // final String itemNumber = request.getParameter("item_number");//购买数量 // final String paymentDate = request.getParameter("payment_date");//交易时间 // final String receiverEmail = request.getParameter("receiver_email");//收款人email // final String payerEmail = request.getParameter("payer_email");//付款人email // final String paymentAmount = request.getParameter("mc_gross");//交易钱数 // final String paymentCurrency = request.getParameter("mc_currency");//货币种类 // final String paymentStatus = request.getParameter("payment_status");//交易状态 // final String txnId = request.getParameter("txn_id");//交易id // String custom = request.getParameter("custom");//发送payment请求时候自定义的业务服务器订单号 // log.info("paypal回调参数:itemName:{},itemNumber:{},paymentDate:{},receiverEmail:{}," + // "payerEmail:{},paymentAmount:{},paymentCurrency:{},paymentStatus:{},txnId:{},custom:{}", // itemName,itemNumber,paymentDate,receiverEmail,payerEmail,paymentAmount,paymentCurrency,paymentStatus,txnId,custom); // // trade_no = txnId; // openId = payerEmail; // if ("Completed".equals(paymentStatus)) { // //根据自己业务进行处理(修改订单状态,支付时间等等操作) // log.info("paypal支付成功回调"); // //表示续费,有消费记录id // payFlag = true; // } // }catch (Exception e) { // log.error("paypal支付回调异常,errorMsg:{}", e.getMessage()); // return false; // }finally { // orderService.payResult(order,payFlag,trade_no,openId); // } // return true; // } /** * 创建支付 * * @param paymentEx * @return * @throws PayPalRESTException */ @Transactional(rollbackFor = Exception.class) public Payment createPayment(PayPalmentEx paymentEx, PaypalConfig paypalConfig) throws PayPalRESTException { Transaction transaction = new Transaction(); transaction.setDescription(paymentEx.getDescription()); // 将我们的订单ID保存到支付信息中,用于后面支付回传 if (null != paymentEx.getOrderSn()) { transaction.setCustom(paymentEx.getOrderSn()); } //订单价格 Amount amount = new Amount(); amount.setCurrency(paypalConfig.getCurrency()); // 支付的总价,paypal会校验 total = subTotal + tax + ... amount.setTotal(paymentEx.getOrderTotal().toString()); // 设置各种费用 Details details = new Details(); // 商品总价 if (paymentEx.getSubTotal() != null) { details.setSubtotal(paymentEx.getSubTotal().toString()); } // 税费 if (paymentEx.getTax() != null) { details.setTax(paymentEx.getTax().toString()); } amount.setDetails(details); transaction.setAmount(amount); ItemList itemList = new ItemList(); // 收货地址 PaypalOrderAddressEx orderAddress = paymentEx.getPaypayOrderAddressEx(); if (orderAddress != null) { ShippingAddress shippingAddress = new ShippingAddress(); if (StringUtils.isNotEmpty(orderAddress.getFirstName()) && StringUtils.isNotEmpty(orderAddress.getLastName())) { shippingAddress.setRecipientName(orderAddress.getFirstName() + "." + orderAddress.getLastName()); } shippingAddress.setCountryCode(orderAddress.getCountryCode()); shippingAddress.setState(orderAddress.getState()); shippingAddress.setCity(orderAddress.getCity()); shippingAddress.setLine1(orderAddress.getAddress()); shippingAddress.setPhone(orderAddress.getPhone()); shippingAddress.setPostalCode(orderAddress.getPostalCode()); itemList.setShippingAddress(shippingAddress); itemList.setShippingPhoneNumber(orderAddress.getPhone()); } // 商品明细 List orderItemList = paymentEx.getPaypalOrderItemExList(); if (orderItemList != null && orderItemList.size() > 0) { List items = new ArrayList<>(); for (PaypalOrderItemEx orderItemEx : orderItemList) { Item item = new Item(); item.setSku(orderItemEx.getSku()); item.setName(orderItemEx.getName()); item.setPrice(orderItemEx.getPrice().toString()); item.setQuantity(String.valueOf(orderItemEx.getQuantity())); item.setCurrency(paypalConfig.getCurrency()); items.add(item); } itemList.setItems(items); transaction.setItemList(itemList); } List transactions = new ArrayList<>(); transactions.add(transaction); // 支付信息 Payer payer = new Payer(); payer.setPaymentMethod(PaypalPaymentMethod.paypal.toString()); Payment payment = new Payment(); //刷新accessToken时间; APIContext apiContext = new APIContext("Bearer " + getAccessToken(paypalConfig)); Map sdkConfig = new HashMap<>(); sdkConfig.put("mode", paypalConfig.getMode()); apiContext.setConfigurationMap(sdkConfig); payment.setIntent(PaypalPaymentIntent.sale.toString()); payment.setPayer(payer); payment.setTransactions(transactions); //回调地址 RedirectUrls redirectUrls = new RedirectUrls(); redirectUrls.setReturnUrl(paypalConfig.getSuccessUrl()); redirectUrls.setCancelUrl(paypalConfig.getCancelUrl()); payment.setRedirectUrls(redirectUrls); return payment.create(apiContext); } /** * 执行支付 * * @param paymentId * @param payerId * @return * @throws PayPalRESTException */ public Payment executePayment(String paymentId, String payerId,PaypalConfig paypalConfig) throws PayPalRESTException { Payment payment = new Payment(); payment.setId(paymentId); PaymentExecution paymentExecute = new PaymentExecution(); paymentExecute.setPayerId(payerId); APIContext apiContext = new APIContext("Bearer " + getAccessToken(paypalConfig)); Map sdkConfig = new HashMap<>(); sdkConfig.put("mode", paypalConfig.getMode()); apiContext.setConfigurationMap(sdkConfig); return payment.execute(apiContext, paymentExecute); } /**      * 获取token      * 了解更多:https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/      * @return      */ private String getAccessToken(PaypalConfig paypalConfig) { BufferedReader reader = null; try { URL url = new URL(UrlUtils.TOKEN_URL); String authorization = paypalConfig.getClientId() + ":" + paypalConfig.getSecret(); authorization = Base64.encodeBase64String(authorization.getBytes()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST");// 提交模式 //设置请求头header conn.setRequestProperty("Accept", "application/json"); conn.setRequestProperty("Accept-Language", "en_US"); conn.setRequestProperty("Authorization", "Basic " + authorization); // conn.setConnectTimeout(10000);//连接超时 单位毫秒 // conn.setReadTimeout(2000);//读取超时 单位毫秒 conn.setDoOutput(true);// 是否输入参数 String params = "grant_type=client_credentials"; conn.getOutputStream().write(params.getBytes());// 输入参数 InputStreamReader inStream = new InputStreamReader(conn.getInputStream()); reader = new BufferedReader(inStream); StringBuilder result = new StringBuilder(); String lineTxt = null; while ((lineTxt = reader.readLine()) != null) { result.append(lineTxt); } reader.close(); //log.info("getAccessToken:" + accessTokey); return JSONObject.parseObject(result.toString()).getString("access_token"); } catch (Exception err) { err.printStackTrace(); } finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } public String getPaymentDetails(String paymentId,PaypalConfig paypalConfig) { BufferedReader reader = null; try { URL url = new URL(UrlUtils.PAYMENT_DETAIL + paymentId); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET");// 提交模式 //设置请求头header conn.setRequestProperty("Accept", "application/json"); conn.setRequestProperty("Authorization", "Bearer " + getAccessToken(paypalConfig)); // conn.setConnectTimeout(10000);//连接超时 单位毫秒 // conn.setReadTimeout(2000);//读取超时 单位毫秒 InputStreamReader inStream = new InputStreamReader(conn.getInputStream()); reader = new BufferedReader(inStream); StringBuilder result = new StringBuilder(); String lineTxt = null; while ((lineTxt = reader.readLine()) != null) { result.append(lineTxt); } reader.close(); return result.toString(); } catch (Exception err) { err.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } public boolean verifyPayment(String paymentId,PaypalConfig paypalConfig){ //从PayPal获取付款详情 String str = getPaymentDetails(paymentId,paypalConfig); JSONObject detail = JSONObject.parseObject(str); //校验订单是否完成 if("approved".equals(detail.getString("state"))){ JSONObject transactions = detail.getJSONArray("transactions").getJSONObject(0); JSONObject amount = transactions.getJSONObject("amount"); JSONArray relatedResources = transactions.getJSONArray("related_resources"); //从数据库查询总金额与Paypal校验支付总金额 double total = 0; if( total != amount.getDouble("total") ){ return false; } //校验交易货币类型 String currency = "USD"; if( !currency.equals(amount.getString("currency")) ){ return false; } //校验每个子订单是否完成 for (int i = 0,j = relatedResources.size(); i < j; i++) { JSONObject sale = relatedResources.getJSONObject(i).getJSONObject("sale"); if( !"completed".equals(sale.getString("state")) ){ System.out.println("子订单未完成,订单状态:"+sale.getString("state")); } } return true; } return false; } }