zoujiajian 1 年之前
父节点
当前提交
b867fc342d

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/order/VipOrderDonService.java

@@ -20,4 +20,6 @@ public interface VipOrderDonService extends IService<VipOrderDon> {
 	AliPayParams aliPay(AlipayOrderDonReq re) throws Exception;
 
 	void aliPayNotify(Map<String, String> params) throws Exception;
+
+	void orderNotify(VipOrderDon orderDon);
 }

+ 5 - 0
netflix-service/src/main/java/com/cyksj/service/order/impl/VipOrderDonServiceImpl.java

@@ -159,6 +159,11 @@ public class VipOrderDonServiceImpl extends ServiceImpl<VipOrderDonMapper, VipOr
 		unifiedHandlerOrderNotify(orderDon);
 	}
 
+	@Override
+	public void orderNotify(VipOrderDon orderDon) {
+		unifiedHandlerOrderNotify(orderDon);
+	}
+
 	private void unifiedHandlerOrderNotify(VipOrderDon orderDon) {
 		orderDon.setStatus(VipOrderDon.Status.complete);
 		this.updateById(orderDon);

+ 119 - 0
netflix-service/src/main/java/com/cyksj/service/paypal/PayPalService.java

@@ -8,9 +8,11 @@ import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.entity.PaypalPayConfig;
+import com.cyksj.model.entity.VipOrderDon;
 import com.cyksj.model.request.OrderRefundReq;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.order.OrderDonService;
+import com.cyksj.service.order.VipOrderDonService;
 import com.paypal.api.payments.Currency;
 import com.paypal.api.payments.*;
 import com.paypal.base.rest.APIContext;
@@ -48,6 +50,7 @@ public class PayPalService{
 
     private final GoodsDonSkuMapper skuMapper;
 
+    private final VipOrderDonService vipOrderDonService;
 
     private static final String SANDBOX_URL = "https://api-m.sandbox.paypal.com";
     private static final String LIVE_URL = "https://api-m.paypal.com";
@@ -220,4 +223,120 @@ public class PayPalService{
         return false;
     }
 
+    public Payment createVipPayment(Long orderId, String successUrl) throws PayPalRESTException {
+        VipOrderDon orderDon = vipOrderDonService.getById(orderId);
+        redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
+        BigDecimal money = orderDon.getMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN);
+        orderDon.setAbroadMoney(money);
+        orderDon.setType(VipOrderDon.Type.PAYPAL);
+        vipOrderDonService.updateById(orderDon);
+        if (VipOrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
+            throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"该订单已支付");
+        }
+        PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
+        // Set payer details
+        Payer payer = new Payer();
+        payer.setPaymentMethod("paypal");
+
+        // Set redirect URLs
+        RedirectUrls redirectUrls = new RedirectUrls();
+
+        redirectUrls.setCancelUrl(paypalPayConfig.getCancelUrl());
+        String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applet/vip/orders/paypal/notify";
+        //成功回调地址(自己写的/pay/success)
+        redirectUrls.setReturnUrl(returnUrl);
+
+        Transaction transaction = new Transaction();
+        transaction.setDescription("");
+        transaction.setCustom(orderDon.getId().toString());
+
+        //订单价格
+        Amount amount = new Amount();
+        amount.setCurrency("USD");
+        // 支付的总价,paypal会校验 total = subTotal + tax + ...
+        BigDecimal totalMoney = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
+        amount.setTotal(totalMoney.toString());
+        // 设置各种费用
+        Details details = new Details();
+        //商品总价
+        details.setSubtotal(totalMoney.toString());
+
+        amount.setDetails(details);
+        transaction.setAmount(amount);
+
+
+        // Add transaction to a list
+        List<Transaction> transactions = new ArrayList<Transaction>();
+        transactions.add(transaction);
+
+        // Add payment details
+        Payment payment = new Payment();
+
+        payment.setIntent("sale");
+        payment.setPayer(payer);
+        payment.setRedirectUrls(redirectUrls);
+        payment.setTransactions(transactions);
+        return payment.create(this.getAPIContext(paypalPayConfig.getClientId(),paypalPayConfig.getClientSecret(),paypalPayConfig.getMode()));
+    }
+
+    public String successVipPayment(String paymentId, String payerId, PaypalPayConfig paypalPayConfig) throws Exception {
+        log.info("paypal回调 paymentId:{},payerId:{}", paymentId, payerId);
+        Payment payment = null;
+        try {
+            payment = this.executePayment(paymentId, payerId, paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
+        } catch (PayPalRESTException e) {
+            log.error("支付回调失败", e);
+            payment = Payment.get(getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode()), paymentId);
+        }
+
+        PayerInfo payerInfo = payment.getPayer().getPayerInfo();
+        log.info("paypal 支付回调 用户信息:{}", payerInfo);
+        //支付成功
+        if ("approved".equals(payment.getState())) {
+            //paypal 交易id
+            Sale sale = payment.getTransactions().get(0).getRelatedResources().get(0).getSale();
+            log.info("paypal 支付回调 订单信息:{}", sale);
+            Currency transactionFee = sale.getTransactionFee();
+            String transationId = sale.getId();
+            String orderId = payment.getTransactions().get(0).getCustom();
+            //更新订单支付状态
+            VipOrderDon orderDon = vipOrderDonService.getById(orderId);
+            orderDon.setTransactionId(transationId);
+            orderDon.setPayTime(new Date());
+            orderDon.setAbroadTransactionFee(new BigDecimal(transactionFee.getValue()).multiply(BigDecimal.valueOf(100)));
+            vipOrderDonService.orderNotify(orderDon);
+            log.info("支付成功订单:" + orderId + ",支付交易号:" + transationId);
+            log.info("支付成功订单:" + orderId + ",返回参数:" + payment);
+
+            THREAD_POOL.execute(() -> {
+                try {
+                    APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
+                    String baseUrl = "live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL;
+                    URL url = new URL(baseUrl + "/v1/shipping/trackers-batch");
+                    HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
+                    httpConn.setRequestMethod("POST");
+                    httpConn.setRequestProperty("Content-Type", "application/json");
+                    httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
+                    httpConn.setDoOutput(true);
+                    OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
+                    writer.write("{\"trackers\": [{ \"transaction_id\": \"" + transationId + "\", \"status\": \"SHIPPED\"}]}");
+                    writer.flush();
+                    writer.close();
+                    httpConn.getOutputStream().close();
+
+                    InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
+                    Scanner s = new Scanner(responseStream).useDelimiter("\\A");
+                    String response = s.hasNext() ? s.next() : "";
+                    log.info("添加物流信息 response:{}", response);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+
+            });
+
+            return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
+        }
+        log.info("支付失败返回参数:" + Jsons.toJson(payment));
+        return paypalPayConfig.getCancelUrl();
+    }
 }

+ 131 - 5
netflix-service/src/main/java/com/cyksj/service/paypal/PaypalV2Service.java

@@ -1,25 +1,22 @@
 package com.cyksj.service.paypal;
 
-import cn.hutool.json.JSONObject;
 import com.cyksj.common.exception.BusinessRuntimeException;
 import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
 import com.cyksj.common.util.Jsons;
 import com.cyksj.enums.GatewayApiCode;
-import com.cyksj.enums.GatewayResponse;
 import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.model.entity.GoodsDonSku;
 import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.entity.PaypalPayConfig;
+import com.cyksj.model.entity.VipOrderDon;
 import com.cyksj.redis.RedisService;
 import com.cyksj.service.order.OrderDonService;
-import com.paypal.api.payments.Amount;
-import com.paypal.api.payments.Sale;
+import com.cyksj.service.order.VipOrderDonService;
 import com.paypal.base.rest.APIContext;
 import com.paypal.base.rest.OAuthTokenCredential;
 import com.paypal.base.rest.PayPalRESTException;
 import com.paypal.core.PayPalHttpClient;
 import com.paypal.http.HttpResponse;
-import com.paypal.http.serializer.Json;
 import com.paypal.orders.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -52,6 +49,9 @@ public class PaypalV2Service {
     private final RedisService redisService;
 
     private final GoodsDonSkuMapper skuMapper;
+
+    private final VipOrderDonService vipOrderDonService;
+
     private static final String SANDBOX_URL = "https://api-m.sandbox.paypal.com";
 
     private static final String LIVE_URL = "https://api-m.paypal.com";
@@ -269,4 +269,130 @@ public class PaypalV2Service {
         apiContext.setConfigurationMap(sdkConfig);
         return apiContext;
     }
+
+    public String createVipPayment(Long orderId, String successUrl) {
+        VipOrderDon orderDon = vipOrderDonService.getById(orderId);
+        redisService.set(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId,successUrl,RedisService.key.ABROAD_SUCCESS_URL.getTimeout());
+        BigDecimal money = orderDon.getMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN);
+        orderDon.setAbroadMoney(money);
+        orderDon.setType(VipOrderDon.Type.PAYPAL);
+        vipOrderDonService.updateById(orderDon);
+        if (VipOrderDon.Status.hasPayment.equals(orderDon.getStatus())) {
+            throw new BusinessRuntimeException(GatewayApiCode.METADATA_SYSTEM_ERROR.getCode(),"该订单已支付");
+        }
+        PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
+        PayPalClient payPalClient = new PayPalClient();
+        // 设置环境沙盒或生产
+        PayPalHttpClient client = payPalClient.client(paypalPayConfig.getMode(), paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret());
+
+        //回调参数(支付成功success路径所携带的参数)
+        Map<String, String> sParaTemp = new HashMap<String, String>();
+
+        sParaTemp.put("orderId", orderId.toString());
+
+        String returnUrl = "https://" + paypalPayConfig.getHost() + "/8081/api/applet/vip/orders/paypalV2/notify";
+
+        // 配置请求参数
+        OrderRequest orderRequest = new OrderRequest();
+        orderRequest.checkoutPaymentIntent("CAPTURE");
+        List<PurchaseUnitRequest> purchaseUnits = new ArrayList<>();
+        BigDecimal totalMoney = money.divide(new BigDecimal(100), 2, RoundingMode.HALF_DOWN);
+        purchaseUnits.add(new PurchaseUnitRequest().referenceId(orderId.toString()).amountWithBreakdown(new AmountWithBreakdown().currencyCode("USD").value(totalMoney.toString())));
+        orderRequest.purchaseUnits(purchaseUnits);
+        orderRequest.applicationContext(new ApplicationContext()
+                .landingPage(LANDINGPAGE)
+                .userAction(USERACTION)
+                .returnUrl(returnUrl)
+                .cancelUrl(paypalPayConfig.getCancelUrl()));
+        OrdersCreateRequest request = new OrdersCreateRequest().requestBody(orderRequest);
+
+        HttpResponse<Order> response;
+        try {
+            response = client.execute(request);
+            Order order = response.result();
+            String payHref = null;
+            String status = order.status();
+            if (status.equals("CREATED")) {
+                List<LinkDescription> links = order.links();
+                for (LinkDescription linkDescription : links) {
+                    if (linkDescription.rel().equals("approve")) {
+                        payHref = linkDescription.href();
+                    }
+                }
+            }
+            return payHref;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public String successVipPayment(String token, String payerId, PaypalPayConfig paypalPayConfig) throws Exception {
+        log.info("paypalV2回调 token:{},payerId:{}", token, payerId);
+        //捕获订单 进行支付
+        HttpResponse<Order> response = null;
+        OrdersCaptureRequest ordersCaptureRequest = new OrdersCaptureRequest(token);
+        ordersCaptureRequest.requestBody(new OrderRequest());
+
+        PayPalClient payPalClient = new PayPalClient();
+        try {
+            response = payPalClient.client(paypalPayConfig.getMode(), paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret()).execute(ordersCaptureRequest);
+            Order result = response.result();
+            log.info("captureOrder response: {}", result);
+            for (PurchaseUnit purchaseUnit : result.purchaseUnits()) {
+                for (Capture capture : purchaseUnit.payments().captures()) {
+                    if ("COMPLETED".equals(capture.status())) {
+                        //支付成功
+                        // 订单号
+                        String saleId = capture.id();
+                        String fee = capture.sellerReceivableBreakdown().paypalFee().value();
+                        String orderId = purchaseUnit.referenceId();
+                        String json = Jsons.toJson(result);
+                        log.info("captureOrder response body: {}", json);
+                        //更新订单支付状态
+                        VipOrderDon orderDon = vipOrderDonService.getById(orderId);
+                        orderDon.setTransactionId(saleId);
+                        orderDon.setPayTime(new Date());
+                        orderDon.setAbroadTransactionFee(new BigDecimal(fee).multiply(BigDecimal.valueOf(100)));
+                        vipOrderDonService.orderNotify(orderDon);
+                        log.info("支付成功订单:"+orderId+",支付交易号:"+saleId);
+
+                        THREAD_POOL.execute(()->{
+                            try {
+                                APIContext apiContext = this.getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(), paypalPayConfig.getMode());
+                                String baseUrl = "live".equals(paypalPayConfig.getMode()) ? LIVE_URL : SANDBOX_URL;
+                                URL url = new URL(baseUrl + "/v1/shipping/trackers-batch");
+                                HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
+                                httpConn.setRequestMethod("POST");
+                                httpConn.setRequestProperty("Content-Type", "application/json");
+                                httpConn.setRequestProperty("Authorization", apiContext.getAccessToken());
+                                httpConn.setDoOutput(true);
+                                OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
+                                writer.write("{\"trackers\": [{ \"transaction_id\": \"" + saleId + "\", \"status\": \"SHIPPED\"}]}");
+                                writer.flush();
+                                writer.close();
+                                httpConn.getOutputStream().close();
+
+                                InputStream responseStream = httpConn.getResponseCode() / 100 == 2 ? httpConn.getInputStream() : httpConn.getErrorStream();
+                                Scanner s = new Scanner(responseStream).useDelimiter("\\A");
+                                String res = s.hasNext() ? s.next() : "";
+                                log.info("添加物流信息 response:{}",res);
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+
+                        });
+
+                        return redisService.getStr(RedisService.key.ABROAD_SUCCESS_URL.getName() + orderId);
+                    }
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } catch (Exception e) {
+	        throw new RuntimeException(e);
+        }
+	    log.info("支付失败返回参数:"+ Jsons.toJson(response.result()));
+        return paypalPayConfig.getCancelUrl();
+    }
 }

+ 75 - 4
netflix-web/src/main/java/com/cyksj/web/controller/vip/VipUserOrderController.java

@@ -6,21 +6,25 @@ import com.cyksj.common.util.StringUtil;
 import com.cyksj.dto.Result;
 import com.cyksj.enums.GatewayResponse;
 import com.cyksj.model.dto.AliPayParams;
+import com.cyksj.model.entity.PaypalPayConfig;
 import com.cyksj.model.entity.VipOrderDon;
 import com.cyksj.model.request.AlipayOrderDonReq;
 import com.cyksj.model.request.VipOrderDonPayReq;
 import com.cyksj.model.response.AliPayTradeStatus;
 import com.cyksj.service.order.VipOrderDonService;
+import com.cyksj.service.paypal.PayPalService;
+import com.cyksj.service.paypal.PaypalPayConfigService;
+import com.cyksj.service.paypal.PaypalV2Service;
 import com.cyksj.web.util.StpUserUtil;
+import com.paypal.api.payments.Links;
+import com.paypal.api.payments.Payment;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
@@ -40,6 +44,14 @@ public class VipUserOrderController {
 
 	private final VipOrderDonService vipOrderDonService;
 
+	private final PayPalService payPalService;
+
+	private final PaypalV2Service paypalV2Service;
+
+	private final PaypalPayConfigService paypalPayConfigService;
+
+	private final HttpServletResponse response;
+
 	/**
 	 * 会员预下单
 	 */
@@ -89,6 +101,65 @@ public class VipUserOrderController {
 		return "success";
 	}
 
+
+	/**
+	 * paypal支付
+	 */
+	@PostMapping("/paypal/pay/{orderId}")
+	public Result<String> paypalPay(@PathVariable Long orderId, String successUrl) throws Exception {
+		final String methodName = "paypal支付";
+		log.info("{}[start] orderId:{}",methodName,orderId);
+
+		Payment payment = payPalService.createVipPayment(orderId,successUrl);
+		String payUrl = "/";
+		log.info("paypal links:{}",payment.getLinks());
+		for(Links links : payment.getLinks()){
+			if("approval_url".equals(links.getRel())){
+				// 客户付款登陆地址
+				String payPalUrl = links.getHref();
+				log.info("PayPal调起支付成功[end]:{}", orderId);
+				payUrl = payPalUrl;
+			}
+		}
+
+		log.info("paypal支付成功[end]");
+
+		return GatewayResponse.SUCCESS.newBuilder().toResult(payUrl);
+	}
+
+	/**
+	 * paypal支付回调
+	 */
+	@RequestMapping(value = "/paypal/notify")
+	public void successPay(@RequestParam(value = "paymentId") String paymentId, @RequestParam(value = "PayerID") String PayerID) throws Exception {
+		PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
+		response.sendRedirect(payPalService.successVipPayment(paymentId,PayerID,paypalPayConfig));
+	}
+
+	/**
+	 * paypalV2支付
+	 */
+	@PostMapping("/paypalV2/pay/{orderId}")
+	public Result<String> paypalV2Pay(@PathVariable Long orderId,String successUrl) throws Exception {
+		final String methodName = "paypal支付";
+		log.info("{}[start] orderId:{}",methodName,orderId);
+
+		String payUrl = paypalV2Service.createVipPayment(orderId,successUrl);
+		log.info("paypal links:{}",payUrl);
+		log.info("paypal支付成功[end]");
+
+		return GatewayResponse.SUCCESS.newBuilder().toResult(payUrl);
+	}
+
+	/**
+	 * paypalV2支付回调
+	 */
+	@RequestMapping(value = "/paypalV2/notify")
+	public void successV2Pay(@RequestParam(value = "token") String token, @RequestParam(value = "PayerID") String PayerID) throws Exception {
+		PaypalPayConfig paypalPayConfig = paypalPayConfigService.getById(1);
+		response.sendRedirect(paypalV2Service.successVipPayment(token,PayerID,paypalPayConfig));
+	}
+
 	/**
 	 * 获取支付宝回调参数
 	 */