diff --git a/wfc-modules/wfc-payment/pom.xml b/wfc-modules/wfc-payment/pom.xml index 5806320..c7f4395 100644 --- a/wfc-modules/wfc-payment/pom.xml +++ b/wfc-modules/wfc-payment/pom.xml @@ -104,9 +104,19 @@ - com.github.javen205 - IJPay-PayPal - ${ijapy.version} + com.paypal.sdk + paypal-server-sdk + 1.0.0 + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/domain/PayPalBean.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/domain/PayPalBean.java index 4857cea..64cb494 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/domain/PayPalBean.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/domain/PayPalBean.java @@ -1,5 +1,6 @@ package org.wfc.payment.domain; +import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -9,53 +10,11 @@ import org.springframework.stereotype.Component; * * @author cyc */ +@Data @Component @ConfigurationProperties(prefix = "paypal") public class PayPalBean { private String clientId; - private String secret; + private String clientSecret; private Boolean sandBox; - private String domain; - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getSecret() { - return secret; - } - - public void setSecret(String secret) { - this.secret = secret; - } - - public Boolean getSandBox() { - return sandBox; - } - - public void setSandBox(Boolean sandBox) { - this.sandBox = sandBox; - } - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - @Override - public String toString() { - return "PayPalBean{" + - "clientId='" + clientId + '\'' + - ", secret='" + secret + '\'' + - ", sandBox=" + sandBox + - ", domain='" + domain + '\'' + - '}'; - } } diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/controller/PayPalController.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/controller/PayPalController.java index a5db896..d03fcea 100644 --- a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/controller/PayPalController.java +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/controller/PayPalController.java @@ -1,297 +1,82 @@ -/** - * - *

PayPal 支付示例

- * - * @author cyc - */ package org.wfc.payment.pay.paypal.controller; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.ijpay.core.IJPayHttpResponse; -import com.ijpay.core.kit.HttpKit; -import com.ijpay.core.kit.PayKit; -import com.ijpay.paypal.PayPalApi; -import com.ijpay.paypal.PayPalApiConfig; -import com.ijpay.paypal.PayPalApiConfigKit; -import com.ijpay.paypal.accesstoken.AccessToken; -import com.ijpay.paypal.accesstoken.AccessTokenKit; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; +import com.paypal.sdk.Environment; +import com.paypal.sdk.PaypalServerSdkClient; +import com.paypal.sdk.authentication.ClientCredentialsAuthModel; +import com.paypal.sdk.models.Order; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Bean; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.wfc.common.core.domain.R; import org.wfc.payment.domain.PayPalBean; +import org.wfc.payment.pay.paypal.service.IPayPalService; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import javax.annotation.Resource; -@Controller -@RequestMapping("/payPal") +@Slf4j +@RestController public class PayPalController { - private Logger log = LoggerFactory.getLogger(this.getClass()); - @Autowired - PayPalBean payPalBean; + @Resource + private PayPalBean payPalBean; - private final static String RETURN_URL = "/payPal/return"; - private final static String CANCEL_URL = "/payPal/cancel"; - - @RequestMapping("test") - @ResponseBody - public PayPalBean test() { - return payPalBean; + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); } - public PayPalApiConfig getConfig() { - PayPalApiConfig config = new PayPalApiConfig(); - config.setClientId(payPalBean.getClientId()); - config.setSecret(payPalBean.getSecret()); - config.setSandBox(payPalBean.getSandBox()); - config.setDomain(payPalBean.getDomain()); - PayPalApiConfigKit.setThreadLocalApiConfig(config); - return config; - } + @Bean + public PaypalServerSdkClient paypalClient() { + return new PaypalServerSdkClient.Builder() +// .loggingConfig(builder -> builder +// .level(Level.DEBUG) +// .requestConfig(logConfigBuilder -> logConfigBuilder.body(true)) +// .responseConfig(logConfigBuilder -> logConfigBuilder.headers(true))) + .httpClientConfig(configBuilder -> configBuilder + .timeout(0)) + .environment(payPalBean.getSandBox() ? Environment.SANDBOX : Environment.PRODUCTION) + .clientCredentialsAuth(new ClientCredentialsAuthModel.Builder( + payPalBean.getClientId(), + payPalBean.getClientSecret()) + .build()) + .build(); + } - @RequestMapping(value = "/getAccessToken") - @ResponseBody - public AccessToken getAccessToken() { - try { - getConfig(); - return AccessTokenKit.get(); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - @RequestMapping(value = "/createOrder") - @ResponseBody - public void createOrder(HttpServletResponse response) { - try { - PayPalApiConfig config = getConfig(); + @RestController + @RequestMapping("/paypal") + public class CheckoutController { - //参数请求参数文档 https://developer.paypal.com/docs/api/orders/v2/#orders_create - Map dataMap = new HashMap<>(); - dataMap.put("intent", "CAPTURE"); + @Resource + private IPayPalService payPalService; - ArrayList> list = new ArrayList<>(); - - Map amount = new HashMap<>(); - amount.put("currency_code", "USD"); - amount.put("value", "0.01"); - - Map itemMap = new HashMap<>(); - itemMap.put("amount", amount); - - list.add(itemMap); - - dataMap.put("purchase_units", list); - - Map card = new HashMap<>(); - card.put("name", "test buyer"); - card.put("number", "4231220385792723"); - card.put("security_code", "123"); - card.put("expiry", "2029-07"); - - Map experienceContext = new HashMap<>(); - experienceContext.put("cancel_url", config.getDomain().concat(CANCEL_URL)); - experienceContext.put("return_url", config.getDomain().concat(RETURN_URL)); - Map> paymentSource = new HashMap<>(); - paymentSource.put("experience_context",experienceContext); - paymentSource.put("card",card); - -// dataMap.put("payment_source", paymentSource); - - String data = JSONUtil.toJsonStr(dataMap); - log.info(data); - IJPayHttpResponse resData = PayPalApi.createOrder(config, data); - log.info(resData.toString()); - if (resData.getStatus() == 201) { - String resultStr = resData.getBody(); - - JSONObject jsonObject = JSONUtil.parseObj(resultStr); - JSONArray links = jsonObject.getJSONArray("links"); - for (int i = 0; i < links.size(); i++) { - JSONObject item = links.getJSONObject(i); - String rel = item.getStr("rel"); - String href = item.getStr("href"); - if ("approve".equalsIgnoreCase(rel)) { - response.sendRedirect(href); - break; - } - } + @PostMapping("/orders") + public R createOrder(@RequestParam Long orderId) { + try { +// String cart = objectMapper.writeValueAsString(request.get("cart")); + Order response = payPalService.createOrder(orderId); + return R.ok(response); + } catch (Exception e) { + log.error("Error creating paypal order", e); + return R.fail(e.getMessage()); } - } catch (Exception e) { - e.printStackTrace(); } - } - @RequestMapping(value = "/updateOrder") - @ResponseBody - public String updateOrder(@RequestParam("id") String id) { - try { - PayPalApiConfig config = getConfig(); - // https://developer.paypal.com/docs/api/orders/v2/#orders_patch - - ArrayList> updateData = new ArrayList<>(); - - Map itemMap = new HashMap<>(); - itemMap.put("op", "replace"); - itemMap.put("path", "/purchase_units/@reference_id=='default'/amount"); - - Map amount = new HashMap<>(); - amount.put("currency_code", "USD"); - amount.put("value", "199.00"); - - itemMap.put("value", amount); - - updateData.add(itemMap); - - String data = JSONUtil.toJsonStr(updateData); - log.info(data); - IJPayHttpResponse resData = PayPalApi.updateOrder(config, id, data); - log.info(resData.toString()); - if (resData.getStatus() == 204) { - return "success"; + @PostMapping("/orders/{paypalOrderId}/capture/{orderId}") + public R captureOrder(@PathVariable String paypalOrderId, @PathVariable Long orderId) { + try { + Order response = payPalService.captureOrders(paypalOrderId, orderId); + return R.ok(response); + } catch (Exception e) { + log.error("Error creating paypal capture", e); + return R.fail(e.getMessage()); } - return "接口请求错误码为:" + resData.getStatus(); - } catch (Exception e) { - e.printStackTrace(); } - return null; - } - @RequestMapping(value = "/queryOrder") - @ResponseBody - public String queryOrder(@RequestParam("id") String id) { - try { - PayPalApiConfig config = getConfig(); - IJPayHttpResponse response = PayPalApi.queryOrder(config, id); - log.info(response.toString()); - if (response.getStatus() == 200) { - return response.getBody(); - } else { - return "接口请求错误码为:" + response.getStatus(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/captureOrder") - @ResponseBody - public String captureOrder(@RequestParam("id") String id) { - try { - PayPalApiConfig config = getConfig(); - IJPayHttpResponse response = PayPalApi.captureOrder(config, id, ""); - log.info(response.toString()); - if (response.getStatus() == 200 || response.getStatus() == 201) { - return response.getBody(); - } else { - return "接口请求错误码为:" + response.getStatus(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/captureQuery") - @ResponseBody - public String captureQuery(@RequestParam("captureId") String captureId) { - try { - PayPalApiConfig config = getConfig(); - IJPayHttpResponse response = PayPalApi.captureQuery(config, captureId); - log.info(response.toString()); - if (response.getStatus() == 200) { - return response.getBody(); - } else { - return "接口请求错误码为:" + response.getStatus(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/refund") - @ResponseBody - public String refund(@RequestParam("id") String id) { - try { - PayPalApiConfig config = getConfig(); - System.out.println("id>" + id); - - Map map = new HashMap<>(); - map.put("invoice_id", PayKit.generateStr()); - map.put("note_to_payer", "test product"); - - Map amount = new HashMap<>(); - amount.put("value", "1.00"); - amount.put("currency_code", "USD"); - - map.put("amount", amount); - - String data = JSONUtil.toJsonStr(map); - log.info("refund data:" + data); - IJPayHttpResponse response = PayPalApi.refund(config, id, data); - log.info(response.toString()); - if (response.getStatus() == 201) { - return response.getBody(); - } else { - return "接口请求错误码为:" + response.getStatus(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/refundQuery") - @ResponseBody - public String refundQuery(@RequestParam("id") String id) { - try { - PayPalApiConfig config = getConfig(); - IJPayHttpResponse response = PayPalApi.refundQuery(config, id); - log.info(response.toString()); - if (response.getStatus() == 200) { - return response.getBody(); - } else { - return "接口请求错误码为:" + response.getStatus(); - } - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/return") - @ResponseBody - public String returnUrl(HttpServletRequest request) { - try { - String token = request.getParameter("token"); - String payerId = request.getParameter("PayerID"); - log.info("token:" + token); - log.info("payerId:" + payerId); - return token; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @RequestMapping(value = "/cancel") - @ResponseBody - public String cancelUrl(HttpServletRequest request, HttpServletResponse response) { - String readData = HttpKit.readData(request); - System.out.println(readData); - return readData; } } diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/IPayPalService.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/IPayPalService.java new file mode 100644 index 0000000..95d4938 --- /dev/null +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/IPayPalService.java @@ -0,0 +1,17 @@ +package org.wfc.payment.pay.paypal.service; + +import com.paypal.sdk.exceptions.ApiException; +import com.paypal.sdk.models.Order; + +import java.io.IOException; + +/** + * @author: cyc + * @since: 2025-04-23 + */ +public interface IPayPalService { + + Order createOrder(Long orderId) throws IOException, ApiException; + + Order captureOrders(String paypalOrderId, Long orderId) throws IOException, ApiException; +} diff --git a/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/impl/PaypalServiceImpl.java b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/impl/PaypalServiceImpl.java new file mode 100644 index 0000000..5d3c8b7 --- /dev/null +++ b/wfc-modules/wfc-payment/src/main/java/org/wfc/payment/pay/paypal/service/impl/PaypalServiceImpl.java @@ -0,0 +1,83 @@ +package org.wfc.payment.pay.paypal.service.impl; + +import com.paypal.sdk.PaypalServerSdkClient; +import com.paypal.sdk.controllers.OrdersController; +import com.paypal.sdk.exceptions.ApiException; +import com.paypal.sdk.http.response.ApiResponse; +import com.paypal.sdk.models.AmountWithBreakdown; +import com.paypal.sdk.models.CaptureOrderInput; +import com.paypal.sdk.models.CheckoutPaymentIntent; +import com.paypal.sdk.models.CreateOrderInput; +import com.paypal.sdk.models.Order; +import com.paypal.sdk.models.OrderRequest; +import com.paypal.sdk.models.PurchaseUnitRequest; +import org.springframework.stereotype.Service; +import org.wfc.common.core.domain.R; +import org.wfc.payment.pay.paypal.service.IPayPalService; +import org.wfc.user.api.RemoteUUserService; +import org.wfc.user.api.domain.vo.UOrderVo; + +import javax.annotation.Resource; +import java.io.IOException; +import java.math.RoundingMode; +import java.util.Arrays; + +/** + * @author: cyc + * @since: 2025-04-23 + */ +@Service +public class PaypalServiceImpl implements IPayPalService { + + @Resource + private PaypalServerSdkClient client; + + @Resource + private RemoteUUserService remoteUUserService; + + @Override + public Order createOrder(Long orderId) throws IOException, ApiException { + String amount = getAmountByOrder(orderId); + CreateOrderInput createOrderInput = new CreateOrderInput.Builder( + null, + new OrderRequest.Builder( + CheckoutPaymentIntent.CAPTURE, + Arrays.asList( + new PurchaseUnitRequest.Builder( + new AmountWithBreakdown.Builder( + "USD", + amount) + .build()) + .build())) + .build()) + .build(); + + OrdersController ordersController = client.getOrdersController(); + + ApiResponse apiResponse = ordersController.createOrder(createOrderInput); + + return apiResponse.getResult(); + } + + private String getAmountByOrder(Long orderId) { + R orderRes = remoteUUserService.getOrderById(orderId); + UOrderVo orderVo = orderRes.getData(); + if (orderVo == null) { + return null; + } + return orderVo.getOrderAmount().setScale(2, RoundingMode.HALF_UP).toString(); + } + + @Override + public Order captureOrders(String paypalOrderId, Long orderId) throws IOException, ApiException { + CaptureOrderInput ordersCaptureInput = new CaptureOrderInput.Builder( + paypalOrderId, + null) + .build(); + OrdersController ordersController = client.getOrdersController(); + ApiResponse apiResponse = ordersController.captureOrder(ordersCaptureInput); + + remoteUUserService.paySuccess(orderId, "inner"); + return apiResponse.getResult(); + } +} diff --git a/wfc-modules/wfc-payment/src/main/resources/application.yml b/wfc-modules/wfc-payment/src/main/resources/application.yml index 4b708ba..78722e6 100644 --- a/wfc-modules/wfc-payment/src/main/resources/application.yml +++ b/wfc-modules/wfc-payment/src/main/resources/application.yml @@ -72,3 +72,8 @@ wxpay: partnerKey: certPath: domain: http://192.168.9.50/u + +paypal: + client-id: AfPgwFAmo9K7KCqiiGpNRCyQMSxI6V33eH-nEMnVndJNVEYOEOEn5wSPkHUybfzcjDLnBejt-RKnIfqX + client_secret: EOYQzSGuMaTMWodcppZUTz9v3H9j38yYiv8bmj4kLZl5NiSUJ0AJJuGlA1CU4oDtEX6jNdGNhsMCiAcN + sandBox: true