移除PayPal支付功能,仅保留支付宝支付

- 删除PayPalService.java和PayPalController.java
- 从PaymentMethod枚举中移除PAYPAL选项
- 移除PaymentController和PaymentApiController中的PayPal相关代码
- 移除前端PayPal支付选项和相关API
- 清理配置文件中的PayPal配置
- 修复OrderController中的PayPal引用错误
This commit is contained in:
AIGC Developer
2025-11-04 11:06:08 +08:00
parent d5f7569a3a
commit 6d834d3385
44 changed files with 89 additions and 648 deletions

View File

@@ -211,3 +211,4 @@ ngrok http 8080
- IJPay文档https://github.com/Javen205/IJPay - IJPay文档https://github.com/Javen205/IJPay

View File

@@ -272,3 +272,4 @@ if (result.success) {
安全和用户体验都得到了提升! 安全和用户体验都得到了提升!

View File

@@ -292,3 +292,4 @@ grep "img2vid_abc123def456" logs/application.log

View File

@@ -293,3 +293,4 @@ public TaskQueue addTextToVideoTask(String username, String taskId) {

View File

@@ -36,5 +36,6 @@ public class PasswordChecker {

View File

@@ -284,3 +284,4 @@ ResourceNotFound.TemplateNotFound
- 创建邮件模板并配置template-id - 创建邮件模板并配置template-id

View File

@@ -302,3 +302,4 @@ const startPolling = (taskId) => {

View File

@@ -172,3 +172,4 @@ const updateWork = async (workId, updateData) => {

View File

@@ -17,11 +17,6 @@ ALIPAY_PUBLIC_KEY=alipay_public_key
ALIPAY_NOTIFY_URL=https://yourdomain.com/api/payments/alipay/notify ALIPAY_NOTIFY_URL=https://yourdomain.com/api/payments/alipay/notify
ALIPAY_RETURN_URL=https://yourdomain.com/api/payments/alipay/return ALIPAY_RETURN_URL=https://yourdomain.com/api/payments/alipay/return
# PayPal配置
PAYPAL_CLIENT_ID=your_paypal_client_id
PAYPAL_CLIENT_SECRET=your_paypal_client_secret
PAYPAL_RETURN_URL=https://yourdomain.com/api/payments/paypal/return
PAYPAL_CANCEL_URL=https://yourdomain.com/api/payments/paypal/cancel
# 日志配置 # 日志配置
LOG_FILE_PATH=./logs/application.log LOG_FILE_PATH=./logs/application.log

View File

@@ -436,5 +436,6 @@ MIT License

View File

@@ -34,3 +34,4 @@ console.log('App.vue 加载成功')

View File

@@ -47,14 +47,6 @@ export const handleAlipayCallback = (params) => {
return api.post('/payments/alipay/callback', params) return api.post('/payments/alipay/callback', params)
} }
// PayPal支付API
export const createPayPalPayment = (paymentData) => {
return api.post(`/payments/paypal/create`, paymentData)
}
export const handlePayPalCallback = (params) => {
return api.post('/payment/paypal/callback', params)
}
// 支付统计API // 支付统计API
export const getPaymentStats = () => { export const getPaymentStats = () => {

View File

@@ -60,3 +60,4 @@ export const getWorkStats = () => {

View File

@@ -95,5 +95,6 @@

View File

@@ -23,17 +23,6 @@
</div> </div>
<span>Alipay扫码支付</span> <span>Alipay扫码支付</span>
</div> </div>
<div
class="payment-method"
:class="{ active: selectedMethod === 'paypal' }"
@click="selectMethod('paypal')"
>
<div class="method-icon paypal-icon">
<el-icon><CreditCard /></el-icon>
</div>
<span>PayPal支付</span>
</div>
</div> </div>
<!-- 金额显示 --> <!-- 金额显示 -->
@@ -127,8 +116,8 @@ const handlePay = async () => {
const paymentData = { const paymentData = {
orderId: props.orderId, orderId: props.orderId,
amount: props.amount.toString(), amount: props.amount.toString(),
method: selectedMethod.value.toUpperCase(), method: 'ALIPAY',
description: `${props.title} - ${selectedMethod.value === 'alipay' ? '支付宝' : 'PayPal'}支付` description: `${props.title} - 支付宝支付`
} }
console.log('=== 开始支付流程 ===') console.log('=== 开始支付流程 ===')
@@ -143,7 +132,6 @@ const handlePay = async () => {
const paymentId = createResponse.data.data.id const paymentId = createResponse.data.data.id
console.log('2. 支付订单创建成功ID', paymentId) console.log('2. 支付订单创建成功ID', paymentId)
if (selectedMethod.value === 'alipay') {
ElMessage.info('正在生成支付宝二维码...') ElMessage.info('正在生成支付宝二维码...')
console.log('3. 创建支付宝支付...') console.log('3. 创建支付宝支付...')
@@ -181,11 +169,6 @@ const handlePay = async () => {
ElMessage.error(alipayResponse.data?.message || '生成二维码失败') ElMessage.error(alipayResponse.data?.message || '生成二维码失败')
emit('pay-error', new Error(alipayResponse.data?.message || '生成二维码失败')) emit('pay-error', new Error(alipayResponse.data?.message || '生成二维码失败'))
} }
} else {
// PayPal支付处理
ElMessage.info('PayPal支付功能开发中...')
emit('pay-error', new Error('PayPal支付功能暂未开放'))
}
} else { } else {
console.error('创建支付订单失败:', createResponse) console.error('创建支付订单失败:', createResponse)

View File

@@ -49,18 +49,6 @@
<el-icon><CreditCard /></el-icon> <el-icon><CreditCard /></el-icon>
支付宝 支付宝
</el-radio> </el-radio>
<el-radio value="PAYPAL">
<el-icon><CreditCard /></el-icon>
PayPal
</el-radio>
<el-radio value="WECHAT">
<el-icon><CreditCard /></el-icon>
微信支付
</el-radio>
<el-radio value="UNIONPAY">
<el-icon><CreditCard /></el-icon>
银联支付
</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
@@ -103,30 +91,6 @@
<p>支持支付宝扫码支付和网页支付</p> <p>支持支付宝扫码支付和网页支付</p>
</div> </div>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="6">
<div class="payment-method-info">
<el-icon size="32" color="#0070BA"><CreditCard /></el-icon>
<h5>PayPal</h5>
<p>支持PayPal账户支付和信用卡支付</p>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="6">
<div class="payment-method-info">
<el-icon size="32" color="#07C160"><CreditCard /></el-icon>
<h5>微信支付</h5>
<p>支持微信扫码支付和H5支付</p>
</div>
</el-col>
<el-col :xs="24" :sm="12" :md="6">
<div class="payment-method-info">
<el-icon size="32" color="#E6A23C"><CreditCard /></el-icon>
<h5>银联支付</h5>
<p>支持银联卡支付和网银支付</p>
</div>
</el-col>
</el-row> </el-row>
</el-card> </el-card>
</div> </div>

View File

@@ -19,12 +19,6 @@ public class PaymentConfig {
return new AliPayConfig(); return new AliPayConfig();
} }
@Bean
@ConfigurationProperties(prefix = "paypal")
public PayPalConfig payPalConfig() {
return new PayPalConfig();
}
/** /**
* 支付宝配置 * 支付宝配置
*/ */
@@ -64,34 +58,4 @@ public class PaymentConfig {
public void setAliPayRootCertPath(String aliPayRootCertPath) { this.aliPayRootCertPath = aliPayRootCertPath; } public void setAliPayRootCertPath(String aliPayRootCertPath) { this.aliPayRootCertPath = aliPayRootCertPath; }
} }
/**
* PayPal支付配置
*/
public static class PayPalConfig {
private String clientId;
private String clientSecret;
private String mode;
private String returnUrl;
private String cancelUrl;
private String domain;
// Getters and Setters
public String getClientId() { return clientId; }
public void setClientId(String clientId) { this.clientId = clientId; }
public String getClientSecret() { return clientSecret; }
public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; }
public String getMode() { return mode; }
public void setMode(String mode) { this.mode = mode; }
public String getReturnUrl() { return returnUrl; }
public void setReturnUrl(String returnUrl) { this.returnUrl = returnUrl; }
public String getCancelUrl() { return cancelUrl; }
public void setCancelUrl(String cancelUrl) { this.cancelUrl = cancelUrl; }
public String getDomain() { return domain; }
public void setDomain(String domain) { this.domain = domain; }
}
} }

View File

@@ -1,9 +1,9 @@
package com.example.demo.controller; package com.example.demo.controller;
import com.example.demo.model.*; import java.math.BigDecimal;
import com.example.demo.service.OrderService; import java.util.ArrayList;
import com.example.demo.service.PaymentService; import java.util.Optional;
import jakarta.validation.Valid;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -15,11 +15,24 @@ import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
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 java.math.BigDecimal; import com.example.demo.model.Order;
import java.util.ArrayList; import com.example.demo.model.OrderItem;
import java.util.Optional; import com.example.demo.model.OrderStatus;
import com.example.demo.model.OrderType;
import com.example.demo.model.Payment;
import com.example.demo.model.PaymentMethod;
import com.example.demo.model.User;
import com.example.demo.service.OrderService;
import com.example.demo.service.PaymentService;
import jakarta.validation.Valid;
@Controller @Controller
@RequestMapping("/orders") @RequestMapping("/orders")
@@ -362,8 +375,6 @@ public class OrderController {
// 根据支付方式跳转到相应的支付页面 // 根据支付方式跳转到相应的支付页面
if (paymentMethod == PaymentMethod.ALIPAY) { if (paymentMethod == PaymentMethod.ALIPAY) {
return "redirect:/payment/alipay/create?paymentId=" + savedPayment.getId(); return "redirect:/payment/alipay/create?paymentId=" + savedPayment.getId();
} else if (paymentMethod == PaymentMethod.PAYPAL) {
return "redirect:/payment/paypal/create?paymentId=" + savedPayment.getId();
} else { } else {
model.addAttribute("error", "不支持的支付方式"); model.addAttribute("error", "不支持的支付方式");
return "redirect:/orders/" + id; return "redirect:/orders/" + id;

View File

@@ -1,162 +0,0 @@
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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.RestController;
/**
* PayPal支付控制器
* 基于IJPay实现
*/
@RestController
@RequestMapping("/api/payments/paypal")
public class PayPalController {
private static final Logger logger = LoggerFactory.getLogger(PayPalController.class);
/**
* 创建支付订单
*/
@PostMapping("/create-order")
public ResponseEntity<Map<String, Object>> createOrder(@RequestParam String outTradeNo,
@RequestParam String totalAmount,
@RequestParam String subject,
@RequestParam String body) {
Map<String, Object> response = new HashMap<>();
try {
// TODO: 实现PayPal订单创建逻辑
// 这里需要根据实际的PayPal API进行实现
response.put("success", true);
response.put("message", "PayPal订单创建功能待实现");
response.put("outTradeNo", outTradeNo);
response.put("totalAmount", totalAmount);
response.put("subject", subject);
logger.info("PayPal订单创建请求: outTradeNo={}, totalAmount={}", outTradeNo, totalAmount);
} catch (Exception e) {
logger.error("PayPal订单创建失败", e);
response.put("success", false);
response.put("message", "订单创建失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 捕获支付
*/
@PostMapping("/capture")
public ResponseEntity<Map<String, Object>> captureOrder(@RequestParam String orderId) {
Map<String, Object> response = new HashMap<>();
try {
// TODO: 实现PayPal支付捕获逻辑
response.put("success", true);
response.put("message", "PayPal支付捕获功能待实现");
response.put("orderId", orderId);
logger.info("PayPal支付捕获请求: orderId={}", orderId);
} catch (Exception e) {
logger.error("PayPal支付捕获失败", e);
response.put("success", false);
response.put("message", "支付捕获失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 查询订单
*/
@GetMapping("/query")
public ResponseEntity<Map<String, Object>> queryOrder(@RequestParam String orderId) {
Map<String, Object> response = new HashMap<>();
try {
// TODO: 实现PayPal订单查询逻辑
response.put("success", true);
response.put("message", "PayPal订单查询功能待实现");
response.put("orderId", orderId);
logger.info("PayPal订单查询请求: orderId={}", orderId);
} catch (Exception e) {
logger.error("PayPal订单查询失败", e);
response.put("success", false);
response.put("message", "订单查询失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 退款
*/
@PostMapping("/refund")
public ResponseEntity<Map<String, Object>> refund(@RequestParam String captureId,
@RequestParam String refundAmount,
@RequestParam String refundReason) {
Map<String, Object> response = new HashMap<>();
try {
// TODO: 实现PayPal退款逻辑
response.put("success", true);
response.put("message", "PayPal退款功能待实现");
response.put("captureId", captureId);
response.put("refundAmount", refundAmount);
logger.info("PayPal退款请求: captureId={}, amount={}", captureId, refundAmount);
} catch (Exception e) {
logger.error("PayPal退款失败", e);
response.put("success", false);
response.put("message", "退款失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 支付成功回调
*/
@GetMapping("/return")
public ResponseEntity<Map<String, Object>> returnUrl(HttpServletRequest request) {
Map<String, Object> response = new HashMap<>();
try {
String token = request.getParameter("token");
String payerId = request.getParameter("PayerID");
logger.info("PayPal支付成功回调: token={}, payerId={}", token, payerId);
response.put("success", true);
response.put("message", "PayPal支付回调功能待实现");
response.put("token", token);
response.put("payerId", payerId);
} catch (Exception e) {
logger.error("PayPal支付回调处理失败", e);
response.put("success", false);
response.put("message", "支付处理失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
/**
* 支付取消回调
*/
@GetMapping("/cancel")
public ResponseEntity<Map<String, Object>> cancelUrl(HttpServletRequest request) {
Map<String, Object> response = new HashMap<>();
try {
String token = request.getParameter("token");
logger.info("PayPal支付取消: token={}", token);
response.put("success", false);
response.put("message", "PayPal支付取消功能待实现");
response.put("token", token);
} catch (Exception e) {
logger.error("PayPal支付取消处理失败", e);
response.put("success", false);
response.put("message", "支付取消处理失败: " + e.getMessage());
}
return ResponseEntity.ok(response);
}
}

View File

@@ -22,7 +22,6 @@ import org.springframework.web.bind.annotation.RestController;
import com.example.demo.model.Payment; import com.example.demo.model.Payment;
import com.example.demo.model.PaymentStatus; import com.example.demo.model.PaymentStatus;
import com.example.demo.service.AlipayService; import com.example.demo.service.AlipayService;
import com.example.demo.service.PayPalService;
import com.example.demo.service.PaymentService; import com.example.demo.service.PaymentService;
@RestController @RestController
@@ -37,9 +36,6 @@ public class PaymentApiController {
@Autowired @Autowired
private AlipayService alipayService; private AlipayService alipayService;
@Autowired
private PayPalService payPalService;
/** /**
* 获取用户的支付记录 * 获取用户的支付记录
@@ -418,50 +414,6 @@ public class PaymentApiController {
} }
} }
/**
* 创建PayPal支付
*/
@PostMapping("/paypal/create")
public ResponseEntity<Map<String, Object>> createPayPalPayment(
@RequestBody Map<String, Object> paymentData,
Authentication authentication) {
try {
String username;
if (authentication != null && authentication.isAuthenticated()) {
username = authentication.getName();
} else {
return ResponseEntity.badRequest()
.body(createErrorResponse("请先登录后再创建支付"));
}
Long paymentId = Long.valueOf(paymentData.get("paymentId").toString());
Payment payment = paymentService.findById(paymentId)
.orElseThrow(() -> new RuntimeException("支付记录不存在"));
// 检查权限
if (!payment.getUser().getUsername().equals(username)) {
return ResponseEntity.status(403)
.body(createErrorResponse("无权限操作此支付记录"));
}
// 调用PayPal接口创建支付
String paymentUrl = payPalService.createPayment(payment);
Map<String, Object> response = new HashMap<>();
response.put("success", true);
response.put("message", "PayPal支付创建成功");
response.put("data", Map.of("paymentUrl", paymentUrl));
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("创建PayPal支付失败", e);
return ResponseEntity.badRequest()
.body(createErrorResponse("创建PayPal支付失败: " + e.getMessage()));
}
}
private Map<String, Object> createErrorResponse(String message) { private Map<String, Object> createErrorResponse(String message) {
Map<String, Object> response = new HashMap<>(); Map<String, Object> response = new HashMap<>();
response.put("success", false); response.put("success", false);

View File

@@ -15,14 +15,12 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; 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.ResponseBody;
import com.example.demo.model.Payment; import com.example.demo.model.Payment;
import com.example.demo.model.PaymentMethod; import com.example.demo.model.PaymentMethod;
import com.example.demo.model.User; import com.example.demo.model.User;
import com.example.demo.service.AlipayService; import com.example.demo.service.AlipayService;
import com.example.demo.service.PayPalService;
import com.example.demo.service.PaymentService; import com.example.demo.service.PaymentService;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@@ -40,9 +38,6 @@ public class PaymentController {
@Autowired @Autowired
private AlipayService alipayService; private AlipayService alipayService;
@Autowired
private PayPalService payPalService;
/** /**
* 显示支付页面 * 显示支付页面
*/ */
@@ -78,7 +73,6 @@ public class PaymentController {
} }
// 根据支付方式创建支付 // 根据支付方式创建支付
String redirectUrl;
if (payment.getPaymentMethod() == PaymentMethod.ALIPAY) { if (payment.getPaymentMethod() == PaymentMethod.ALIPAY) {
Map<String, Object> paymentResult = alipayService.createPayment(payment); Map<String, Object> paymentResult = alipayService.createPayment(payment);
if (paymentResult.containsKey("qrCode")) { if (paymentResult.containsKey("qrCode")) {
@@ -86,9 +80,6 @@ public class PaymentController {
return "redirect:/payment/qr?qrCode=" + paymentResult.get("qrCode"); return "redirect:/payment/qr?qrCode=" + paymentResult.get("qrCode");
} }
return "redirect:/payment/error"; return "redirect:/payment/error";
} else if (payment.getPaymentMethod() == PaymentMethod.PAYPAL) {
redirectUrl = payPalService.createPayment(payment);
return "redirect:" + redirectUrl;
} else { } else {
model.addAttribute("error", "不支持的支付方式"); model.addAttribute("error", "不支持的支付方式");
model.addAttribute("paymentMethods", PaymentMethod.values()); model.addAttribute("paymentMethods", PaymentMethod.values());
@@ -158,65 +149,6 @@ public class PaymentController {
} }
} }
/**
* PayPal支付返回
*/
@GetMapping("/paypal/return")
public String paypalReturn(@RequestParam("paymentId") String paymentId,
@RequestParam("PayerID") String payerId,
Model model) {
try {
boolean success = payPalService.executePayment(paymentId, payerId);
if (success) {
Payment payment = paymentService.findByExternalTransactionId(paymentId)
.orElseThrow(() -> new RuntimeException("支付记录不存在"));
model.addAttribute("payment", payment);
model.addAttribute("success", true);
return "payment/result";
} else {
model.addAttribute("error", "支付执行失败");
return "payment/result";
}
} catch (Exception e) {
logger.error("处理PayPal支付返回失败", e);
model.addAttribute("error", "支付处理失败:" + e.getMessage());
return "payment/result";
}
}
/**
* PayPal支付取消
*/
@GetMapping("/paypal/cancel")
public String paypalCancel(Model model) {
model.addAttribute("error", "支付已取消");
return "payment/result";
}
/**
* PayPal Webhook通知
*/
@PostMapping("/paypal/webhook")
@ResponseBody
public String paypalWebhook(HttpServletRequest request) {
try {
Map<String, String> params = request.getParameterMap().entrySet().stream()
.collect(java.util.stream.Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue()[0]
));
boolean success = payPalService.handleWebhook(params);
return success ? "success" : "fail";
} catch (Exception e) {
logger.error("处理PayPal Webhook失败", e);
return "fail";
}
}
/** /**
* 支付记录列表 * 支付记录列表
*/ */

View File

@@ -67,3 +67,4 @@ public class MailMessage {
} }

View File

@@ -1,8 +1,7 @@
package com.example.demo.model; package com.example.demo.model;
public enum PaymentMethod { public enum PaymentMethod {
ALIPAY("支付宝"), ALIPAY("支付宝");
PAYPAL("PayPal");
private final String displayName; private final String displayName;

View File

@@ -201,3 +201,4 @@ public class PointsFreezeRecord {

View File

@@ -269,3 +269,4 @@ public class TaskQueue {

View File

@@ -261,3 +261,4 @@ public class TaskStatus {

View File

@@ -69,3 +69,4 @@ public interface TaskStatusRepository extends JpaRepository<TaskStatus, Long> {

View File

@@ -38,5 +38,6 @@ public class PlainTextPasswordEncoder implements PasswordEncoder {

View File

@@ -1,202 +0,0 @@
package com.example.demo.service;
import com.example.demo.model.Payment;
import com.example.demo.model.PaymentMethod;
import com.example.demo.model.PaymentStatus;
import com.example.demo.repository.PaymentRepository;
import com.paypal.api.payments.*;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
@Service
public class PayPalService {
private static final Logger logger = LoggerFactory.getLogger(PayPalService.class);
private final PaymentRepository paymentRepository;
@Value("${paypal.client-id}")
private String clientId;
@Value("${paypal.client-secret}")
private String clientSecret;
@Value("${paypal.mode}")
private String mode;
@Value("${paypal.return-url}")
private String returnUrl;
@Value("${paypal.cancel-url}")
private String cancelUrl;
public PayPalService(PaymentRepository paymentRepository) {
this.paymentRepository = paymentRepository;
}
/**
* 创建PayPal支付订单
*/
public String createPayment(Payment payment) {
try {
// 设置支付状态
payment.setStatus(PaymentStatus.PENDING);
payment.setPaymentMethod(PaymentMethod.PAYPAL);
payment.setOrderId(generateOrderId());
payment.setReturnUrl(returnUrl);
// 保存支付记录
paymentRepository.save(payment);
// 创建API上下文
APIContext apiContext = new APIContext(clientId, clientSecret, mode);
// 创建支付金额
Amount amount = new Amount();
amount.setCurrency(payment.getCurrency());
amount.setTotal(payment.getAmount().toString());
// 创建交易
Transaction transaction = new Transaction();
transaction.setAmount(amount);
transaction.setDescription(payment.getDescription() != null ? payment.getDescription() : "商品支付");
// 创建交易列表
List<Transaction> transactions = new ArrayList<>();
transactions.add(transaction);
// 创建支付者
Payer payer = new Payer();
payer.setPaymentMethod("paypal");
// 创建支付
com.paypal.api.payments.Payment paypalPayment = new com.paypal.api.payments.Payment();
paypalPayment.setIntent("sale");
paypalPayment.setPayer(payer);
paypalPayment.setTransactions(transactions);
// 设置重定向URL
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setReturnUrl(returnUrl + "?paymentId={PAY_ID}&PayerID={PAYER_ID}");
redirectUrls.setCancelUrl(cancelUrl);
paypalPayment.setRedirectUrls(redirectUrls);
// 创建支付
com.paypal.api.payments.Payment createdPayment = paypalPayment.create(apiContext);
// 更新支付记录
payment.setExternalTransactionId(createdPayment.getId());
paymentRepository.save(payment);
logger.info("PayPal支付订单创建成功订单号{}PayPal ID{}",
payment.getOrderId(), createdPayment.getId());
// 获取批准URL
for (Links link : createdPayment.getLinks()) {
if ("approval_url".equals(link.getRel())) {
return link.getHref();
}
}
throw new RuntimeException("未找到PayPal批准URL");
} catch (PayPalRESTException e) {
logger.error("PayPal API调用异常", e);
payment.setStatus(PaymentStatus.FAILED);
paymentRepository.save(payment);
throw new RuntimeException("PayPal支付服务异常" + e.getMessage());
}
}
/**
* 执行PayPal支付
*/
public boolean executePayment(String paymentId, String payerId) {
try {
// 创建API上下文
APIContext apiContext = new APIContext(clientId, clientSecret, mode);
// 创建支付执行
PaymentExecution paymentExecution = new PaymentExecution();
paymentExecution.setPayerId(payerId);
// 获取支付信息
com.paypal.api.payments.Payment payment = com.paypal.api.payments.Payment.get(apiContext, paymentId);
// 执行支付
com.paypal.api.payments.Payment executedPayment = payment.execute(apiContext, paymentExecution);
// 查找支付记录
Payment paymentRecord = paymentRepository.findByExternalTransactionId(paymentId)
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
// 更新支付状态
if ("approved".equals(executedPayment.getState())) {
paymentRecord.setStatus(PaymentStatus.SUCCESS);
paymentRecord.setPaidAt(LocalDateTime.now());
logger.info("PayPal支付成功订单号{}", paymentRecord.getOrderId());
} else {
paymentRecord.setStatus(PaymentStatus.FAILED);
logger.warn("PayPal支付失败订单号{},状态:{}",
paymentRecord.getOrderId(), executedPayment.getState());
}
paymentRepository.save(paymentRecord);
return true;
} catch (PayPalRESTException e) {
logger.error("PayPal支付执行异常", e);
return false;
}
}
/**
* 处理PayPal Webhook通知
*/
public boolean handleWebhook(Map<String, String> params) {
try {
String eventType = params.get("event_type");
String resourceType = params.get("resource_type");
logger.info("收到PayPal Webhook通知事件类型{},资源类型:{}", eventType, resourceType);
if ("PAYMENT.SALE.COMPLETED".equals(eventType) && "sale".equals(resourceType)) {
String paymentId = params.get("resource.id");
// 查找支付记录
Payment payment = paymentRepository.findByExternalTransactionId(paymentId)
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
// 更新支付状态
payment.setStatus(PaymentStatus.SUCCESS);
payment.setPaidAt(LocalDateTime.now());
paymentRepository.save(payment);
logger.info("PayPal Webhook处理成功订单号{}", payment.getOrderId());
return true;
}
return false;
} catch (Exception e) {
logger.error("处理PayPal Webhook异常", e);
return false;
}
}
/**
* 生成订单号
*/
private String generateOrderId() {
return "PP" + System.currentTimeMillis() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
}
}

View File

@@ -38,12 +38,6 @@ alipay.sign-type=RSA2
alipay.notify-url=${ALIPAY_NOTIFY_URL} alipay.notify-url=${ALIPAY_NOTIFY_URL}
alipay.return-url=${ALIPAY_RETURN_URL} alipay.return-url=${ALIPAY_RETURN_URL}
# PayPal配置 (生产环境)
paypal.client-id=${PAYPAL_CLIENT_ID}
paypal.client-secret=${PAYPAL_CLIENT_SECRET}
paypal.mode=live
paypal.return-url=${PAYPAL_RETURN_URL}
paypal.cancel-url=${PAYPAL_CANCEL_URL}
# JWT配置 - 使用环境变量 # JWT配置 - 使用环境变量
jwt.secret=${JWT_SECRET} jwt.secret=${JWT_SECRET}

View File

@@ -28,3 +28,4 @@ CREATE TABLE IF NOT EXISTS task_queue (

View File

@@ -27,3 +27,4 @@ CREATE TABLE IF NOT EXISTS points_freeze_records (

View File

@@ -30,3 +30,4 @@ CREATE TABLE task_status (

View File

@@ -574,5 +574,6 @@

View File

@@ -490,5 +490,6 @@

View File

@@ -529,5 +529,6 @@

View File

@@ -52,15 +52,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6">
<div class="card payment-card h-100" onclick="selectPaymentMethod('PAYPAL')">
<div class="card-body text-center">
<i class="fab fa-paypal payment-icon paypal-icon"></i>
<h5 class="card-title">PayPal</h5>
<p class="card-text">全球领先的在线支付</p>
</div>
</div>
</div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@@ -128,9 +119,6 @@
if (method === 'ALIPAY') { if (method === 'ALIPAY') {
currencySelect.value = 'CNY'; currencySelect.value = 'CNY';
currencySelect.options[0].selected = true; currencySelect.options[0].selected = true;
} else if (method === 'PAYPAL') {
currencySelect.value = 'USD';
currencySelect.options[1].selected = true;
} }
} }

View File

@@ -31,3 +31,4 @@ pause > nul

View File

@@ -58,3 +58,4 @@ public class TestApiConnection {

View File

@@ -17,3 +17,4 @@ except Exception as e:

View File

@@ -25,3 +25,4 @@ else:

View File

@@ -61,3 +61,4 @@ if __name__ == "__main__":

View File

@@ -82,3 +82,4 @@ if __name__ == "__main__":

View File

@@ -17,3 +17,4 @@ except Exception as e: