This commit is contained in:
menxipeng
2025-08-03 16:56:44 +08:00
parent d6c5934dba
commit 85375b7f0c
18 changed files with 1627 additions and 282 deletions

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.mapper;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import java.util.List;
@@ -59,4 +60,20 @@ public interface OrderInfoMapper
* @return 结果
*/
public int deleteOrderInfoByIds(String[] ids);
/**
* 根据订单号查询订单
*
* @param orderId 订单号
* @return 订单信息
*/
public OrderInfo selectOrderByOrderId(String orderId);
/**
* 查询订单列表(包含用户信息和套餐信息)
*
* @param orderInfo 查询条件
* @return 订单列表
*/
public List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
}

View File

@@ -2,6 +2,10 @@ package com.ruoyi.system.service;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import java.util.List;
@@ -61,5 +65,69 @@ public interface IOrderInfoService
*/
public int deleteOrderInfoById(String id);
AjaxResult createOrder(OrderInfo orderInfo);
/**
* 创建订单
*
* @param request 订单创建请求
* @return 结果
*/
AjaxResult createOrder(OrderCreateRequest request);
/**
* 支付订单
*
* @param request 支付请求
* @return 结果
*/
AjaxResult payOrder(PaymentRequest request);
/**
* 完成支付(支付回调)
*
* @param orderId 订单ID
* @param tradeNo 第三方交易号
* @param payType 支付方式
* @return 结果
*/
AjaxResult completePayment(String orderId, String tradeNo, String payType);
/**
* 确认出货
*
* @param orderId 订单ID
* @return 结果
*/
AjaxResult confirmShipment(String orderId);
/**
* 申请退款
*
* @param request 退款请求
* @return 结果
*/
AjaxResult refundOrder(RefundRequest request);
/**
* 查询用户订单列表
*
* @param userId 用户ID
* @return 订单列表
*/
List<OrderInfo> selectUserOrders(Long userId);
/**
* 查询订单详情
*
* @param orderId 订单ID
* @return 订单详情
*/
OrderInfo selectOrderByOrderId(String orderId);
/**
* 查询订单列表(包含用户信息和套餐信息)
*
* @param orderInfo 查询条件
* @return 订单列表
*/
List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo);
}

View File

@@ -1,16 +1,24 @@
package com.ruoyi.system.service.impl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.dto.OrderCreateRequest;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.core.domain.dto.RefundRequest;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.entity.PayStatusEnum;
import com.ruoyi.common.core.domain.vo.OrderInfoVO;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.OrderInfoMapper;
import com.ruoyi.system.service.IOrderInfoService;
import com.ruoyi.system.util.PaymentUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.*;
/**
* 【请填写功能名称】Service业务层处理
@@ -23,6 +31,9 @@ public class OrderInfoServiceImpl implements IOrderInfoService
{
@Autowired
private OrderInfoMapper orderInfoMapper;
@Autowired
private PaymentUtil paymentUtil;
/**
* 查询【请填写功能名称】
@@ -99,13 +110,272 @@ public class OrderInfoServiceImpl implements IOrderInfoService
}
@Override
public AjaxResult createOrder(OrderInfo orderInfo) {
LoginUser userInfo = SecurityUtils.getLoginUser();
if (userInfo != null){
//orderInfo.setPayStatus();
@Transactional
public AjaxResult createOrder(OrderCreateRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderName()) || request.getAmount() == null || request.getAmount() <= 0) {
return AjaxResult.error("订单信息不完整");
}
// 获取当前用户
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
return AjaxResult.error("用户未登录");
}
// 创建订单
OrderInfo orderInfo = new OrderInfo();
orderInfo.setId(UUID.randomUUID().toString().replace("-", ""));
orderInfo.setOrderId(System.currentTimeMillis()); // 使用时间戳作为订单号
orderInfo.setOrderName(request.getOrderName());
orderInfo.setUserId(loginUser.getUserId());
orderInfo.setAmount(request.getAmount());
orderInfo.setPayType(request.getPayType());
orderInfo.setPackageType(request.getPackageType());
orderInfo.setDeviceType(request.getDeviceType());
orderInfo.setClientIp(request.getClientIp());
orderInfo.setPayStatus(PayStatusEnum.CREATE.status); // 1-创建订单
orderInfo.setIdDel(0L);
orderInfo.setVersion(1L);
orderInfo.setCreateTime(DateUtils.getNowDate());
// 保存订单
int result = insertOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("订单创建成功", orderInfo);
} else {
return AjaxResult.error("订单创建失败");
}
} catch (Exception e) {
return AjaxResult.error("订单创建异常: " + e.getMessage());
}
}
return null;
@Override
@Transactional
public AjaxResult payOrder(PaymentRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderId())) {
return AjaxResult.error("订单ID不能为空");
}
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(request.getOrderId());
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.CREATE.getStatus()) {
return AjaxResult.error("订单状态不正确");
}
// 检查用户权限
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null || !loginUser.getUserId().equals(orderInfo.getUserId())) {
return AjaxResult.error("无权限操作此订单");
}
// 调用第三方支付接口
Map<String, Object> paymentResult = processPayment(orderInfo, request);
return AjaxResult.success("支付请求成功", paymentResult);
} catch (Exception e) {
return AjaxResult.error("支付异常: " + e.getMessage());
}
}
@Override
@Transactional
public AjaxResult completePayment(String orderId, String tradeNo, String payType) {
try {
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.CREATE.getStatus()) {
return AjaxResult.error("订单状态不正确");
}
// 更新订单状态
orderInfo.setPayStatus(PayStatusEnum.PENDING.getStatus()); // 2-待出货
orderInfo.setPayTime(DateUtils.getNowDate());
orderInfo.setTradeNo(tradeNo);
orderInfo.setCallTime(DateUtils.getNowDate());
orderInfo.setCallbackContent("支付成功回调");
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 计算服务时间
calculateServiceTime(orderInfo);
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("支付完成");
} else {
return AjaxResult.error("支付完成处理失败");
}
} catch (Exception e) {
return AjaxResult.error("支付完成处理异常: " + e.getMessage());
}
}
@Override
@Transactional
public AjaxResult refundOrder(RefundRequest request) {
try {
// 参数校验
if (StringUtils.isEmpty(request.getOrderId()) || request.getRefundAmount() == null || request.getRefundAmount() <= 0) {
return AjaxResult.error("退款信息不完整");
}
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(request.getOrderId());
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.PENDING.getStatus() && orderInfo.getPayStatus() != PayStatusEnum.WAIT_REFUND.getStatus()) {
return AjaxResult.error("订单状态不允许退款");
}
// 检查退款金额
if (request.getRefundAmount() > orderInfo.getAmount()) {
return AjaxResult.error("退款金额不能大于订单金额");
}
// 检查是否已退款
if (orderInfo.getRefundAmount() != null && orderInfo.getRefundAmount() > 0) {
return AjaxResult.error("订单已退款");
}
// 调用第三方退款接口
boolean refundResult = paymentUtil.processRefund(orderInfo.getOrderId().toString(), request.getRefundAmount(), orderInfo.getPayType());
if (!refundResult) {
return AjaxResult.error("第三方退款失败");
}
// 更新订单退款信息
orderInfo.setRefundAmount(request.getRefundAmount());
orderInfo.setRefundTime(DateUtils.getNowDate());
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 如果是全额退款,更新订单状态
if (request.getRefundAmount().equals(orderInfo.getAmount())) {
orderInfo.setPayStatus(PayStatusEnum.REFUND.getStatus()); // 4-已退款
}
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("退款申请成功");
} else {
return AjaxResult.error("退款申请失败");
}
} catch (Exception e) {
return AjaxResult.error("退款异常: " + e.getMessage());
}
}
@Override
public List<OrderInfo> selectUserOrders(Long userId) {
OrderInfo orderInfo = new OrderInfo();
orderInfo.setUserId(userId);
orderInfo.setIdDel(0L);
return orderInfoMapper.selectOrderInfoList(orderInfo);
}
@Override
public OrderInfo selectOrderByOrderId(String orderId) {
return orderInfoMapper.selectOrderByOrderId(orderId);
}
@Override
public List<OrderInfoVO> selectOrderInfoVOList(OrderInfo orderInfo) {
return orderInfoMapper.selectOrderInfoVOList(orderInfo);
}
@Override
@Transactional
public AjaxResult confirmShipment(String orderId) {
try {
// 查询订单
OrderInfo orderInfo = selectOrderByOrderId(orderId);
if (orderInfo == null) {
return AjaxResult.error("订单不存在");
}
// 检查订单状态
if (orderInfo.getPayStatus() != PayStatusEnum.PENDING.getStatus()) {
return AjaxResult.error("订单状态不正确,只有已支付的订单才能确认出货");
}
// 更新订单状态为已完成
orderInfo.setPayStatus(PayStatusEnum.COMPLETE.getStatus()); // 3-已完成
orderInfo.setUpdateTime(DateUtils.getNowDate());
// 保存订单
int result = updateOrderInfo(orderInfo);
if (result > 0) {
return AjaxResult.success("确认出货成功");
} else {
return AjaxResult.error("确认出货失败");
}
} catch (Exception e) {
return AjaxResult.error("确认出货异常: " + e.getMessage());
}
}
/**
* 处理支付过程
*/
private Map<String, Object> processPayment(OrderInfo orderInfo, PaymentRequest request) {
// 根据支付方式调用相应的支付接口
switch (request.getPayType()) {
case "aliPay":
return paymentUtil.processAliPay(orderInfo, request);
case "wechatPay":
return paymentUtil.processWechatPay(orderInfo, request);
case "applePay":
return paymentUtil.processApplePay(orderInfo, request);
default:
Map<String, Object> errorResult = new HashMap<>();
errorResult.put("error", "不支持的支付方式");
return errorResult;
}
}
/**
* 计算服务时间
*/
private void calculateServiceTime(OrderInfo orderInfo) {
Date now = DateUtils.getNowDate();
orderInfo.setStartTime(now);
// 根据套餐类型计算结束时间
String packageType = orderInfo.getPackageType();
if ("1".equals(packageType)) {
// 包月
orderInfo.setEndTime(DateUtils.addMonths(now, 1));
} else if ("3".equals(packageType)) {
// 包季度
orderInfo.setEndTime(DateUtils.addMonths(now, 3));
} else if ("6".equals(packageType)) {
// 半年
orderInfo.setEndTime(DateUtils.addMonths(now, 6));
} else if ("12".equals(packageType)) {
// 一年
orderInfo.setEndTime(DateUtils.addMonths(now, 12));
}
}
}

View File

@@ -0,0 +1,195 @@
package com.ruoyi.system.util;
import com.ruoyi.common.core.domain.entity.OrderInfo;
import com.ruoyi.common.core.domain.dto.PaymentRequest;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* 支付工具类
*
* @author ruoyi
* @date 2025-01-27
*/
@Component
public class PaymentUtil {
/**
* 处理支付宝支付
*/
public Map<String, Object> processAliPay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用支付宝SDK进行支付
// 这里只是模拟返回支付参数
// 构建支付宝支付参数
Map<String, Object> aliPayParams = new HashMap<>();
aliPayParams.put("out_trade_no", orderInfo.getOrderId().toString());
aliPayParams.put("total_amount", orderInfo.getAmount() / 100.0);
aliPayParams.put("subject", StringUtils.isNotEmpty(request.getSubject()) ? request.getSubject() : orderInfo.getOrderName());
aliPayParams.put("body", StringUtils.isNotEmpty(request.getBody()) ? request.getBody() : "购买VIP会员服务");
aliPayParams.put("timeout_express", (request.getTimeoutMinutes() != null ? request.getTimeoutMinutes() : 30) + "m");
aliPayParams.put("product_code", "QUICK_WAP_WAY");
result.put("paymentUrl", "https://openapi.alipay.com/gateway.do?");
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "aliPay");
result.put("params", aliPayParams);
return result;
}
/**
* 处理微信支付
*/
public Map<String, Object> processWechatPay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用微信支付SDK进行支付
// 这里只是模拟返回支付参数
// 构建微信支付参数
Map<String, Object> wechatPayParams = new HashMap<>();
wechatPayParams.put("out_trade_no", orderInfo.getOrderId().toString());
wechatPayParams.put("total_fee", orderInfo.getAmount());
wechatPayParams.put("body", StringUtils.isNotEmpty(request.getBody()) ? request.getBody() : orderInfo.getOrderName());
wechatPayParams.put("attach", StringUtils.isNotEmpty(request.getAttach()) ? request.getAttach() : "VIP会员服务");
if (StringUtils.isNotEmpty(request.getOpenid())) {
wechatPayParams.put("openid", request.getOpenid());
}
result.put("prepayId", "wx_prepay_id_" + System.currentTimeMillis());
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "wechatPay");
result.put("params", wechatPayParams);
return result;
}
/**
* 处理Apple Pay支付
*/
public Map<String, Object> processApplePay(OrderInfo orderInfo, PaymentRequest request) {
Map<String, Object> result = new HashMap<>();
// TODO: 调用Apple Pay SDK进行支付
// 这里只是模拟返回支付参数
// 构建Apple Pay支付参数
Map<String, Object> applePayParams = new HashMap<>();
applePayParams.put("orderId", orderInfo.getOrderId().toString());
applePayParams.put("amount", orderInfo.getAmount() / 100.0);
applePayParams.put("currency", "CNY");
applePayParams.put("merchantIdentifier", StringUtils.isNotEmpty(request.getMerchantIdentifier()) ?
request.getMerchantIdentifier() : "merchant.com.example");
if (StringUtils.isNotEmpty(request.getPaymentToken())) {
applePayParams.put("paymentToken", request.getPaymentToken());
}
result.put("paymentToken", "apple_payment_token_" + System.currentTimeMillis());
result.put("orderId", orderInfo.getOrderId());
result.put("amount", orderInfo.getAmount());
result.put("payType", "applePay");
result.put("params", applePayParams);
return result;
}
/**
* 验证支付回调
*/
public boolean verifyPaymentCallback(String orderId, String tradeNo, String payType, String signature) {
// TODO: 根据不同的支付方式验证回调签名
// 这里只是模拟验证
if (StringUtils.isEmpty(orderId) || StringUtils.isEmpty(tradeNo) || StringUtils.isEmpty(payType)) {
return false;
}
// 验证签名逻辑
switch (payType) {
case "aliPay":
return verifyAliPayCallback(signature);
case "wechatPay":
return verifyWechatPayCallback(signature);
case "applePay":
return verifyApplePayCallback(signature);
default:
return false;
}
}
/**
* 验证支付宝回调
*/
private boolean verifyAliPayCallback(String signature) {
// TODO: 实现支付宝回调验证
return true;
}
/**
* 验证微信支付回调
*/
private boolean verifyWechatPayCallback(String signature) {
// TODO: 实现微信支付回调验证
return true;
}
/**
* 验证Apple Pay回调
*/
private boolean verifyApplePayCallback(String signature) {
// TODO: 实现Apple Pay回调验证
return true;
}
/**
* 处理退款
*/
public boolean processRefund(String orderId, Long refundAmount, String payType) {
// TODO: 根据不同的支付方式调用相应的退款接口
switch (payType) {
case "aliPay":
return processAliPayRefund(orderId, refundAmount);
case "wechatPay":
return processWechatPayRefund(orderId, refundAmount);
case "applePay":
return processApplePayRefund(orderId, refundAmount);
default:
return false;
}
}
/**
* 处理支付宝退款
*/
private boolean processAliPayRefund(String orderId, Long refundAmount) {
// TODO: 调用支付宝退款接口
return true;
}
/**
* 处理微信支付退款
*/
private boolean processWechatPayRefund(String orderId, Long refundAmount) {
// TODO: 调用微信支付退款接口
return true;
}
/**
* 处理Apple Pay退款
*/
private boolean processApplePayRefund(String orderId, Long refundAmount) {
// TODO: 调用Apple Pay退款接口
return true;
}
}

View File

@@ -151,4 +151,70 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{id}
</foreach>
</delete>
<select id="selectOrderByOrderId" parameterType="String" resultMap="OrderInfoResult">
<include refid="selectOrderInfoVo"/>
where order_id = #{orderId} and id_del = 0
</select>
<resultMap type="OrderInfoVO" id="OrderInfoVOResult">
<result property="orderId" column="order_id" />
<result property="userNickname" column="user_nickname" />
<result property="packageName" column="package_name" />
<result property="amountYuan" column="amount_yuan" />
<result property="payTypeName" column="pay_type_name" />
<result property="startTime" column="start_time" />
<result property="endTime" column="end_time" />
<result property="statusName" column="status_name" />
<result property="createTime" column="create_time" />
</resultMap>
<select id="selectOrderInfoVOList" parameterType="OrderInfo" resultMap="OrderInfoVOResult">
SELECT
o.order_id,
su.nickname as user_nickname,
CASE
WHEN o.package_type = '1' THEN '包月'
WHEN o.package_type = '3' THEN '包季度'
WHEN o.package_type = '6' THEN '半年'
WHEN o.package_type = '12' THEN '一年'
ELSE '未知套餐'
END as package_name,
ROUND(o.amount / 100.0, 2) as amount_yuan,
CASE
WHEN o.pay_type = 'aliPay' THEN '支付宝'
WHEN o.pay_type = 'wechatPay' THEN '微信支付'
WHEN o.pay_type = 'applePay' THEN 'Apple Pay'
ELSE '未知支付方式'
END as pay_type_name,
o.start_time,
o.end_time,
CASE
WHEN o.pay_status = 1 THEN '待支付'
WHEN o.pay_status = 2 THEN '待出货'
WHEN o.pay_status = 3 THEN '待退款'
WHEN o.pay_status = 4 THEN '已退款'
WHEN o.pay_status = 5 THEN '已完成'
ELSE '未知状态'
END as status_name,
o.create_time
FROM order_info o
LEFT JOIN shop_user su ON o.user_id = su.user_id
<where>
o.id_del = 0
<if test="orderId != null "> and o.order_id = #{orderId}</if>
<if test="orderName != null and orderName != ''"> and o.order_name like concat('%', #{orderName}, '%')</if>
<if test="userId != null "> and o.user_id = #{userId}</if>
<if test="amount != null "> and o.amount = #{amount}</if>
<if test="payType != null and payType != ''"> and o.pay_type = #{payType}</if>
<if test="payTime != null "> and o.pay_time = #{payTime}</if>
<if test="payStatus != null "> and o.pay_status = #{payStatus}</if>
<if test="startTime != null "> and o.start_time = #{startTime}</if>
<if test="endTime != null "> and o.end_time = #{endTime}</if>
<if test="packageType != null and packageType != ''"> and o.package_type = #{packageType}</if>
<if test="clientIp != null and clientIp != ''"> and o.client_ip = #{clientIp}</if>
<if test="deviceType != null and deviceType != ''"> and o.device_type = #{deviceType}</if>
</where>
ORDER BY o.create_time DESC
</select>
</mapper>