feat: 添加任务状态级联触发器,优化支付和做同款功能
主要更新: - 添加 MySQL 触发器实现 task_status 表到其他表的状态级联 - 移除控制器中的多表状态检查代码 - 完善做同款功能,支持参数传递 - 支付宝 USD 转 CNY 汇率转换 - 修复状态枚举映射问题 注意: 触发器仅在 task_status 更新时触发,部分代码仍直接更新业务表
This commit is contained in:
@@ -13,518 +13,242 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.example.demo.model.Order;
|
||||
import com.example.demo.model.OrderItem;
|
||||
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.PaymentStatus;
|
||||
import com.example.demo.model.User;
|
||||
import com.example.demo.model.*;
|
||||
import com.example.demo.repository.PaymentRepository;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class PaymentService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PaymentService.class);
|
||||
@Autowired private PaymentRepository paymentRepository;
|
||||
@Autowired private OrderService orderService;
|
||||
@Autowired private UserService userService;
|
||||
@Autowired private AlipayService alipayService;
|
||||
@Autowired(required = false) private PayPalService payPalService;
|
||||
|
||||
@Autowired
|
||||
private PaymentRepository paymentRepository;
|
||||
public Payment save(Payment payment) { return paymentRepository.save(payment); }
|
||||
@Transactional(readOnly = true) public Optional<Payment> findById(Long id) { return paymentRepository.findByIdWithUser(id); }
|
||||
@Transactional(readOnly = true) public Optional<Payment> findByOrderId(String orderId) { return paymentRepository.findByOrderId(orderId); }
|
||||
@Transactional(readOnly = true) public Optional<Payment> findByExternalTransactionId(String id) { return paymentRepository.findByExternalTransactionId(id); }
|
||||
@Transactional(readOnly = true) public List<Payment> findByUserId(Long userId) { return paymentRepository.findByUserIdOrderByCreatedAtDesc(userId); }
|
||||
@Transactional(readOnly = true) public List<Payment> findAll() { return paymentRepository.findAll(); }
|
||||
@Transactional(readOnly = true) public List<Payment> findByStatus(PaymentStatus status) { return paymentRepository.findByStatus(status); }
|
||||
@Transactional(readOnly = true) public long countByUserId(Long userId) { return paymentRepository.countByUserId(userId); }
|
||||
@Transactional(readOnly = true) public long countByStatus(PaymentStatus status) { return paymentRepository.countByStatus(status); }
|
||||
@Transactional(readOnly = true) public long countByUserIdAndStatus(Long userId, PaymentStatus status) { return paymentRepository.countByUserIdAndStatus(userId, status); }
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private AlipayService alipayService;
|
||||
|
||||
@Autowired(required = false)
|
||||
private PayPalService payPalService;
|
||||
|
||||
/**
|
||||
* 保存支付记录
|
||||
*/
|
||||
public Payment save(Payment payment) {
|
||||
try {
|
||||
Payment savedPayment = paymentRepository.save(payment);
|
||||
logger.info("支付记录保存成功,支付ID:{}", savedPayment.getId());
|
||||
return savedPayment;
|
||||
} catch (Exception e) {
|
||||
logger.error("保存支付记录失败:", e);
|
||||
throw new RuntimeException("保存支付记录失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID查找支付记录(包含User信息,避免LazyInitializationException)
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<Payment> findById(Long id) {
|
||||
return paymentRepository.findByIdWithUser(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单ID查找支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<Payment> findByOrderId(String orderId) {
|
||||
return paymentRepository.findByOrderId(orderId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据外部交易ID查找支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Optional<Payment> findByExternalTransactionId(String externalTransactionId) {
|
||||
return paymentRepository.findByExternalTransactionId(externalTransactionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查找支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<Payment> findByUserId(Long userId) {
|
||||
return paymentRepository.findByUserIdOrderByCreatedAtDesc(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找所有支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<Payment> findAll() {
|
||||
return paymentRepository.findAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态查找支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<Payment> findByStatus(PaymentStatus status) {
|
||||
return paymentRepository.findByStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付状态
|
||||
*/
|
||||
public Payment updatePaymentStatus(Long paymentId, PaymentStatus newStatus) {
|
||||
try {
|
||||
Payment payment = paymentRepository.findById(paymentId)
|
||||
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
|
||||
|
||||
PaymentStatus oldStatus = payment.getStatus();
|
||||
payment.setStatus(newStatus);
|
||||
|
||||
if (newStatus == PaymentStatus.SUCCESS) {
|
||||
payment.setPaidAt(LocalDateTime.now());
|
||||
|
||||
// 更新关联订单状态
|
||||
if (payment.getOrder() != null) {
|
||||
orderService.confirmPayment(payment.getOrder().getId(), payment.getExternalTransactionId());
|
||||
}
|
||||
}
|
||||
|
||||
Payment updatedPayment = paymentRepository.save(payment);
|
||||
logger.info("支付状态更新成功,支付ID:{},状态:{} -> {}",
|
||||
paymentId, oldStatus, newStatus);
|
||||
|
||||
return updatedPayment;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("更新支付状态失败:", e);
|
||||
throw new RuntimeException("更新支付状态失败:" + e.getMessage());
|
||||
}
|
||||
Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
|
||||
payment.setStatus(newStatus);
|
||||
if (newStatus == PaymentStatus.SUCCESS) payment.setPaidAt(LocalDateTime.now());
|
||||
return paymentRepository.save(payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认支付成功
|
||||
*/
|
||||
public Payment confirmPaymentSuccess(Long paymentId, String externalTransactionId) {
|
||||
try {
|
||||
Payment payment = paymentRepository.findById(paymentId)
|
||||
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
|
||||
|
||||
payment.setStatus(PaymentStatus.SUCCESS);
|
||||
payment.setPaidAt(LocalDateTime.now());
|
||||
payment.setExternalTransactionId(externalTransactionId);
|
||||
|
||||
Payment confirmedPayment = paymentRepository.save(payment);
|
||||
|
||||
// 更新关联订单状态
|
||||
if (payment.getOrder() != null) {
|
||||
orderService.confirmPayment(payment.getOrder().getId(), externalTransactionId);
|
||||
} else {
|
||||
// 如果没有关联订单,自动创建一个订单
|
||||
createOrderFromPayment(confirmedPayment);
|
||||
}
|
||||
|
||||
// 根据支付金额增加积分
|
||||
addPointsForPayment(confirmedPayment);
|
||||
|
||||
logger.info("支付确认成功,支付ID:{},外部交易ID:{}", paymentId, externalTransactionId);
|
||||
return confirmedPayment;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("确认支付成功失败:", e);
|
||||
throw new RuntimeException("确认支付成功失败:" + e.getMessage());
|
||||
Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
|
||||
|
||||
// 检查是否已经处理过(防止重复增加积分和重复创建订单)
|
||||
if (payment.getStatus() == PaymentStatus.SUCCESS) {
|
||||
logger.info("支付记录已经是成功状态,跳过重复处理: paymentId={}", paymentId);
|
||||
return payment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认支付失败
|
||||
*/
|
||||
public Payment confirmPaymentFailure(Long paymentId, String failureReason) {
|
||||
|
||||
payment.setStatus(PaymentStatus.SUCCESS);
|
||||
payment.setPaidAt(LocalDateTime.now());
|
||||
payment.setExternalTransactionId(externalTransactionId);
|
||||
Payment savedPayment = paymentRepository.save(payment);
|
||||
|
||||
// 支付成功后创建订单
|
||||
try {
|
||||
Payment payment = paymentRepository.findById(paymentId)
|
||||
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
|
||||
|
||||
payment.setStatus(PaymentStatus.FAILED);
|
||||
if (failureReason != null && !failureReason.isEmpty()) {
|
||||
payment.setDescription((payment.getDescription() != null ? payment.getDescription() + "\n" : "") +
|
||||
"失败原因:" + failureReason);
|
||||
}
|
||||
|
||||
Payment failedPayment = paymentRepository.save(payment);
|
||||
logger.info("支付确认失败,支付ID:{},失败原因:{}", paymentId, failureReason);
|
||||
|
||||
return failedPayment;
|
||||
|
||||
createOrderForPayment(savedPayment);
|
||||
} catch (Exception e) {
|
||||
logger.error("确认支付失败失败:", e);
|
||||
throw new RuntimeException("确认支付失败失败:" + e.getMessage());
|
||||
logger.error("支付成功但创建订单失败: paymentId={}, error={}", paymentId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单支付
|
||||
*/
|
||||
public Payment createOrderPayment(Order order, PaymentMethod paymentMethod) {
|
||||
|
||||
// 支付成功后增加用户积分
|
||||
try {
|
||||
Payment payment = new Payment();
|
||||
payment.setOrderId(order.getOrderNumber());
|
||||
payment.setAmount(order.getTotalAmount());
|
||||
payment.setCurrency(order.getCurrency());
|
||||
payment.setPaymentMethod(paymentMethod);
|
||||
payment.setDescription("订单支付 - " + order.getOrderNumber());
|
||||
payment.setUser(order.getUser());
|
||||
payment.setOrder(order);
|
||||
payment.setStatus(PaymentStatus.PENDING);
|
||||
|
||||
Payment savedPayment = paymentRepository.save(payment);
|
||||
logger.info("订单支付创建成功,订单号:{},支付ID:{}", order.getOrderNumber(), savedPayment.getId());
|
||||
|
||||
return savedPayment;
|
||||
|
||||
addPointsForPayment(savedPayment);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建订单支付失败:", e);
|
||||
throw new RuntimeException("创建订单支付失败:" + e.getMessage());
|
||||
logger.error("支付成功但增加积分失败: paymentId={}, error={}", paymentId, e.getMessage(), e);
|
||||
}
|
||||
|
||||
return savedPayment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计支付记录数量
|
||||
* 为支付成功的记录创建订单
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public long countByUserId(Long userId) {
|
||||
return paymentRepository.countByUserId(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定状态的支付记录数量
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public long countByStatus(PaymentStatus status) {
|
||||
return paymentRepository.countByStatus(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计用户指定状态的支付记录数量
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public long countByUserIdAndStatus(Long userId, PaymentStatus status) {
|
||||
return paymentRepository.countByUserIdAndStatus(userId, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付记录
|
||||
*/
|
||||
public void deletePayment(Long paymentId) {
|
||||
try {
|
||||
Payment payment = paymentRepository.findById(paymentId)
|
||||
.orElseThrow(() -> new RuntimeException("支付记录不存在:" + paymentId));
|
||||
|
||||
// 只有失败的支付记录才能删除
|
||||
if (payment.getStatus() != PaymentStatus.FAILED) {
|
||||
throw new RuntimeException("只有失败的支付记录才能删除");
|
||||
}
|
||||
|
||||
paymentRepository.delete(payment);
|
||||
logger.info("支付记录删除成功,支付ID:{}", paymentId);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("删除支付记录失败:", e);
|
||||
throw new RuntimeException("删除支付记录失败:" + e.getMessage());
|
||||
private void createOrderForPayment(Payment payment) {
|
||||
if (payment == null || payment.getUser() == null) {
|
||||
logger.warn("无法创建订单: payment或user为空");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名查找支付记录
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<Payment> findByUsername(String username) {
|
||||
try {
|
||||
logger.info("PaymentService: 开始查找用户 {} 的支付记录", username);
|
||||
|
||||
// 先查找用户
|
||||
User user = userService.findByUsername(username);
|
||||
if (user == null) {
|
||||
logger.error("PaymentService: 用户 {} 不存在", username);
|
||||
throw new RuntimeException("用户不存在: " + username);
|
||||
}
|
||||
|
||||
logger.info("PaymentService: 找到用户 {}, ID: {}", username, user.getId());
|
||||
|
||||
// 查找支付记录
|
||||
List<Payment> payments = paymentRepository.findByUserIdOrderByCreatedAtDesc(user.getId());
|
||||
logger.info("PaymentService: 用户 {} 的支付记录数量: {}", username, payments.size());
|
||||
|
||||
return payments;
|
||||
} catch (Exception e) {
|
||||
logger.error("PaymentService: 根据用户名查找支付记录失败,用户名: {}, 错误: {}", username, e.getMessage(), e);
|
||||
throw new RuntimeException("查找支付记录失败:" + e.getMessage());
|
||||
|
||||
// 检查是否已经关联了订单
|
||||
if (payment.getOrder() != null) {
|
||||
logger.info("支付记录已关联订单,跳过创建: paymentId={}, orderId={}", payment.getId(), payment.getOrder().getId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付
|
||||
*/
|
||||
public Payment createPayment(String username, String orderId, String amountStr, String method) {
|
||||
|
||||
try {
|
||||
logger.info("创建支付 - 用户名: '{}', 订单ID: {}, 金额: {}, 支付方式: {}", username, orderId, amountStr, method);
|
||||
|
||||
User user;
|
||||
try {
|
||||
logger.info("PaymentService - 尝试查找用户: '{}'", username);
|
||||
user = userService.findByUsername(username);
|
||||
logger.info("PaymentService - 用户查找结果: {}", user != null ? "找到用户 '" + user.getUsername() + "'" : "未找到用户");
|
||||
} catch (Exception e) {
|
||||
logger.error("PaymentService - 用户查找异常: {}", username, e);
|
||||
// 如果是匿名用户,创建一个临时用户记录
|
||||
if (username.startsWith("anonymous_")) {
|
||||
user = createAnonymousUser(username);
|
||||
} else {
|
||||
throw new RuntimeException("用户不存在: " + username);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("找到用户: {}", user.getUsername());
|
||||
|
||||
BigDecimal amount = new BigDecimal(amountStr);
|
||||
PaymentMethod paymentMethod = PaymentMethod.valueOf(method);
|
||||
|
||||
logger.info("金额: {}, 支付方式: {}", amount, paymentMethod);
|
||||
|
||||
Payment payment = new Payment();
|
||||
payment.setUser(user);
|
||||
payment.setOrderId(orderId);
|
||||
payment.setAmount(amount);
|
||||
payment.setCurrency("CNY"); // 设置默认货币为人民币
|
||||
payment.setPaymentMethod(paymentMethod);
|
||||
payment.setStatus(PaymentStatus.PENDING);
|
||||
payment.setCreatedAt(LocalDateTime.now());
|
||||
|
||||
Payment savedPayment = save(payment);
|
||||
logger.info("支付记录创建成功: {}", savedPayment.getId());
|
||||
|
||||
// 根据支付方式调用相应的支付服务
|
||||
if (paymentMethod == PaymentMethod.ALIPAY) {
|
||||
try {
|
||||
Map<String, Object> paymentResult = alipayService.createPayment(savedPayment);
|
||||
if (paymentResult.containsKey("qrCode")) {
|
||||
savedPayment.setPaymentUrl(paymentResult.get("qrCode").toString());
|
||||
}
|
||||
save(savedPayment);
|
||||
logger.info("支付宝二维码生成成功: {}", paymentResult.get("qrCode"));
|
||||
} catch (Exception e) {
|
||||
logger.error("调用支付宝支付接口失败:", e);
|
||||
// 不抛出异常,让前端处理
|
||||
}
|
||||
} else if (paymentMethod == PaymentMethod.PAYPAL) {
|
||||
try {
|
||||
if (payPalService == null) {
|
||||
throw new RuntimeException("PayPal服务未配置");
|
||||
}
|
||||
Map<String, Object> paymentResult = payPalService.createPayment(savedPayment);
|
||||
if (paymentResult.containsKey("paymentUrl")) {
|
||||
savedPayment.setPaymentUrl(paymentResult.get("paymentUrl").toString());
|
||||
}
|
||||
if (paymentResult.containsKey("paypalPaymentId")) {
|
||||
savedPayment.setExternalTransactionId(paymentResult.get("paypalPaymentId").toString());
|
||||
}
|
||||
save(savedPayment);
|
||||
logger.info("PayPal支付链接生成成功: {}", paymentResult.get("paymentUrl"));
|
||||
} catch (Exception e) {
|
||||
logger.error("调用PayPal支付接口失败:", e);
|
||||
throw new RuntimeException("创建PayPal支付失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return savedPayment;
|
||||
} catch (Exception e) {
|
||||
logger.error("创建支付失败:", e);
|
||||
throw new RuntimeException("创建支付失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建匿名用户
|
||||
*/
|
||||
private User createAnonymousUser(String username) {
|
||||
try {
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setEmail(username + "@anonymous.com");
|
||||
user.setPasswordHash("anonymous");
|
||||
user.setRole("ROLE_USER");
|
||||
|
||||
return userService.save(user);
|
||||
} catch (Exception e) {
|
||||
logger.error("创建匿名用户失败:", e);
|
||||
throw new RuntimeException("创建匿名用户失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户支付统计
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Map<String, Object> getUserPaymentStats(String username) {
|
||||
try {
|
||||
User user = userService.findByUsername(username);
|
||||
if (user == null) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
}
|
||||
|
||||
Long userId = user.getId();
|
||||
|
||||
Map<String, Object> stats = new HashMap<>();
|
||||
stats.put("totalPayments", paymentRepository.countByUserId(userId));
|
||||
stats.put("successfulPayments", paymentRepository.countByUserIdAndStatus(userId, PaymentStatus.SUCCESS));
|
||||
stats.put("pendingPayments", paymentRepository.countByUserIdAndStatus(userId, PaymentStatus.PENDING));
|
||||
stats.put("failedPayments", paymentRepository.countByUserIdAndStatus(userId, PaymentStatus.FAILED));
|
||||
stats.put("cancelledPayments", paymentRepository.countByUserIdAndStatus(userId, PaymentStatus.CANCELLED));
|
||||
|
||||
return stats;
|
||||
} catch (Exception e) {
|
||||
logger.error("获取用户支付统计失败:", e);
|
||||
throw new RuntimeException("获取支付统计失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付信息增加积分
|
||||
*/
|
||||
private void addPointsForPayment(Payment payment) {
|
||||
try {
|
||||
BigDecimal amount = payment.getAmount();
|
||||
String description = payment.getDescription() != null ? payment.getDescription() : "";
|
||||
Integer pointsToAdd = 0;
|
||||
|
||||
// 优先从描述中识别套餐类型
|
||||
if (description.contains("标准版") || description.contains("standard")) {
|
||||
// 标准版订阅 - 200积分
|
||||
pointsToAdd = 200;
|
||||
logger.info("识别到标准版订阅,奖励 200 积分");
|
||||
} else if (description.contains("专业版") || description.contains("premium")) {
|
||||
// 专业版订阅 - 1000积分
|
||||
pointsToAdd = 1000;
|
||||
logger.info("识别到专业版订阅,奖励 1000 积分");
|
||||
} else {
|
||||
// 如果描述中没有套餐信息,根据金额判断
|
||||
// 标准版订阅 (59-258元) - 200积分
|
||||
if (amount.compareTo(new BigDecimal("59.00")) >= 0 && amount.compareTo(new BigDecimal("259.00")) < 0) {
|
||||
pointsToAdd = 200;
|
||||
logger.info("根据金额 {} 判断为标准版订阅,奖励 200 积分", amount);
|
||||
}
|
||||
// 专业版订阅 (259元以上) - 1000积分
|
||||
else if (amount.compareTo(new BigDecimal("259.00")) >= 0) {
|
||||
pointsToAdd = 1000;
|
||||
logger.info("根据金额 {} 判断为专业版订阅,奖励 1000 积分", amount);
|
||||
} else {
|
||||
logger.warn("支付金额 {} 不在已知套餐范围内,不增加积分", amount);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointsToAdd > 0) {
|
||||
userService.addPoints(payment.getUser().getId(), pointsToAdd);
|
||||
logger.info("✅ 用户 {} 支付 {} 元,成功获得 {} 积分",
|
||||
payment.getUser().getUsername(), amount, pointsToAdd);
|
||||
} else {
|
||||
// 如果金额不在套餐范围内,给予基础积分(1元=1积分)
|
||||
// 这样可以避免用户支付后没有任何积分的情况
|
||||
int basePoints = amount.intValue(); // 1元=1积分
|
||||
if (basePoints > 0) {
|
||||
userService.addPoints(payment.getUser().getId(), basePoints);
|
||||
logger.info("✅ 用户 {} 支付 {} 元(非套餐金额),获得基础积分 {} 积分(按1元=1积分计算)",
|
||||
payment.getUser().getUsername(), amount, basePoints);
|
||||
} else {
|
||||
logger.warn("⚠️ 用户 {} 支付 {} 元,金额过小未获得积分(描述: {})",
|
||||
payment.getUser().getUsername(), amount, description);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("❌ 增加积分失败:", e);
|
||||
// 不抛出异常,避免影响支付流程
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从支付记录自动创建订单
|
||||
*/
|
||||
private void createOrderFromPayment(Payment payment) {
|
||||
try {
|
||||
// 生成订单号
|
||||
String orderNumber = "ORD" + System.currentTimeMillis();
|
||||
|
||||
// 创建订单
|
||||
Order order = new Order();
|
||||
order.setUser(payment.getUser());
|
||||
order.setOrderNumber(orderNumber);
|
||||
order.setOrderNumber("ORD" + System.currentTimeMillis() + payment.getId());
|
||||
order.setTotalAmount(payment.getAmount());
|
||||
order.setCurrency("CNY");
|
||||
order.setStatus(OrderStatus.PAID); // 支付成功,订单状态为已支付
|
||||
order.setOrderType(OrderType.PAYMENT); // 订单类型为支付订单
|
||||
order.setCreatedAt(LocalDateTime.now());
|
||||
order.setUpdatedAt(LocalDateTime.now());
|
||||
order.setCurrency(payment.getCurrency() != null ? payment.getCurrency() : "CNY");
|
||||
order.setStatus(OrderStatus.PAID);
|
||||
order.setPaidAt(LocalDateTime.now());
|
||||
order.setOrderType(OrderType.SUBSCRIPTION);
|
||||
order.setNotes(payment.getDescription() != null ? payment.getDescription() : "会员订阅");
|
||||
|
||||
// 保存订单
|
||||
Order savedOrder = orderService.save(order);
|
||||
// 根据金额设置订单描述
|
||||
BigDecimal amount = payment.getAmount();
|
||||
if (amount != null) {
|
||||
if (amount.compareTo(new BigDecimal("259.00")) >= 0) {
|
||||
order.setNotes("专业版会员订阅 - " + amount + "元");
|
||||
} else if (amount.compareTo(new BigDecimal("59.00")) >= 0) {
|
||||
order.setNotes("标准版会员订阅 - " + amount + "元");
|
||||
}
|
||||
}
|
||||
|
||||
// 创建订单项
|
||||
OrderItem orderItem = new OrderItem();
|
||||
orderItem.setOrder(savedOrder);
|
||||
orderItem.setProductName("支付服务 - " + payment.getPaymentMethod().name());
|
||||
orderItem.setProductDescription("通过" + payment.getPaymentMethod().name() + "完成的支付服务");
|
||||
orderItem.setQuantity(1);
|
||||
orderItem.setUnitPrice(payment.getAmount());
|
||||
orderItem.setSubtotal(payment.getAmount());
|
||||
Order savedOrder = orderService.createOrder(order);
|
||||
|
||||
// 保存订单项
|
||||
orderService.saveOrderItem(orderItem);
|
||||
|
||||
// 更新支付记录,关联到新创建的订单
|
||||
// 关联支付记录和订单
|
||||
payment.setOrder(savedOrder);
|
||||
paymentRepository.save(payment);
|
||||
|
||||
logger.info("从支付记录自动创建订单成功,支付ID:{},订单ID:{},订单号:{}",
|
||||
payment.getId(), savedOrder.getId(), orderNumber);
|
||||
|
||||
logger.info("✅ 订单创建成功: orderId={}, orderNumber={}, paymentId={}",
|
||||
savedOrder.getId(), savedOrder.getOrderNumber(), payment.getId());
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("从支付记录创建订单失败:", e);
|
||||
throw new RuntimeException("创建订单失败:" + e.getMessage());
|
||||
logger.error("创建订单失败: paymentId={}, error={}", payment.getId(), e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据支付金额增加用户积分
|
||||
* 标准版(59元) -> 200积分
|
||||
* 专业版(259元) -> 1000积分
|
||||
*/
|
||||
private void addPointsForPayment(Payment payment) {
|
||||
if (payment == null || payment.getUser() == null) {
|
||||
logger.warn("无法增加积分: payment或user为空");
|
||||
return;
|
||||
}
|
||||
|
||||
java.math.BigDecimal amount = payment.getAmount();
|
||||
if (amount == null) {
|
||||
logger.warn("无法增加积分: 支付金额为空, paymentId={}", payment.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据金额计算积分
|
||||
int points = 0;
|
||||
String planName = "";
|
||||
|
||||
// 专业版订阅 (259元以上) -> 1000积分
|
||||
if (amount.compareTo(new java.math.BigDecimal("259.00")) >= 0) {
|
||||
points = 1000;
|
||||
planName = "专业版";
|
||||
}
|
||||
// 标准版订阅 (59-258元) -> 200积分
|
||||
else if (amount.compareTo(new java.math.BigDecimal("59.00")) >= 0) {
|
||||
points = 200;
|
||||
planName = "标准版";
|
||||
}
|
||||
// 其他金额不增加积分
|
||||
else {
|
||||
logger.info("支付金额不在套餐范围内,不增加积分: amount={}", amount);
|
||||
return;
|
||||
}
|
||||
|
||||
// 增加积分
|
||||
Long userId = payment.getUser().getId();
|
||||
logger.info("开始为用户增加积分: userId={}, points={}, plan={}, paymentId={}", userId, points, planName, payment.getId());
|
||||
|
||||
userService.addPoints(userId, points);
|
||||
|
||||
logger.info("✅ 积分增加成功: userId={}, addedPoints={}, plan={}", userId, points, planName);
|
||||
}
|
||||
|
||||
public Payment confirmPaymentFailure(Long paymentId, String failureReason) {
|
||||
Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
|
||||
payment.setStatus(PaymentStatus.FAILED);
|
||||
return paymentRepository.save(payment);
|
||||
}
|
||||
|
||||
public Payment createOrderPayment(Order order, PaymentMethod paymentMethod) {
|
||||
Payment payment = new Payment();
|
||||
payment.setOrderId(order.getOrderNumber());
|
||||
payment.setAmount(order.getTotalAmount());
|
||||
payment.setCurrency(order.getCurrency());
|
||||
payment.setPaymentMethod(paymentMethod);
|
||||
payment.setUser(order.getUser());
|
||||
payment.setOrder(order);
|
||||
payment.setStatus(PaymentStatus.PENDING);
|
||||
return paymentRepository.save(payment);
|
||||
}
|
||||
|
||||
public void deletePayment(Long paymentId) {
|
||||
Payment payment = paymentRepository.findById(paymentId).orElseThrow(() -> new RuntimeException("Not found"));
|
||||
paymentRepository.delete(payment);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Payment> findByUsername(String username) {
|
||||
User user = userService.findByUsername(username);
|
||||
if (user == null) throw new RuntimeException("User not found");
|
||||
return paymentRepository.findByUserIdOrderByCreatedAtDesc(user.getId());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Payment createPayment(String username, String orderId, String amountStr, String method) {
|
||||
// 检查是否已存在相同 orderId 的支付记录
|
||||
Optional<Payment> existing = paymentRepository.findByOrderId(orderId);
|
||||
if (existing.isPresent()) {
|
||||
Payment existingPayment = existing.get();
|
||||
// 如果已存在且状态是 PENDING,直接返回
|
||||
if (existingPayment.getStatus() == PaymentStatus.PENDING) {
|
||||
logger.info("复用已存在的PENDING支付记录: orderId={}, paymentId={}", orderId, existingPayment.getId());
|
||||
return existingPayment;
|
||||
}
|
||||
// 如果是其他状态,生成新的 orderId
|
||||
orderId = orderId + "_" + System.currentTimeMillis();
|
||||
logger.info("已存在相同orderId但状态为{},生成新orderId: {}", existingPayment.getStatus(), orderId);
|
||||
}
|
||||
|
||||
User user = null;
|
||||
if (username != null) { try { user = userService.findByUsername(username); } catch (Exception e) {} }
|
||||
if (user == null) { user = userService.findByUsernameOrNull(username != null ? username : "anon"); if (user == null) user = createAnonymousUser(username != null ? username : "anon"); }
|
||||
Payment payment = new Payment();
|
||||
payment.setUser(user);
|
||||
payment.setOrderId(orderId);
|
||||
payment.setAmount(new BigDecimal(amountStr));
|
||||
payment.setCurrency("CNY");
|
||||
payment.setPaymentMethod(PaymentMethod.valueOf(method));
|
||||
payment.setStatus(PaymentStatus.PENDING);
|
||||
payment.setCreatedAt(LocalDateTime.now());
|
||||
return paymentRepository.save(payment);
|
||||
}
|
||||
|
||||
private User createAnonymousUser(String username) {
|
||||
User user = new User();
|
||||
user.setUsername(username);
|
||||
user.setEmail(username + "@anon.com");
|
||||
user.setPasswordHash("anon");
|
||||
user.setRole("ROLE_USER");
|
||||
return userService.save(user);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public Map<String, Object> getUserPaymentStats(String username) {
|
||||
User user = userService.findByUsername(username);
|
||||
if (user == null) throw new RuntimeException("User not found");
|
||||
Map<String, Object> stats = new HashMap<>();
|
||||
stats.put("totalPayments", paymentRepository.countByUserId(user.getId()));
|
||||
stats.put("successfulPayments", paymentRepository.countByUserIdAndStatus(user.getId(), PaymentStatus.SUCCESS));
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user