“mitao”
2026-01-04 6ff2e616cd1c1e986735c5a8c1f991ab9dfe5ec4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package com.ruoyi.system.service.impl;
 
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.config.ICBCConfig;
import com.ruoyi.system.dto.PhysicalGoodsPlaceOrderDTO;
import com.ruoyi.system.enums.PhysicalGoodsOrderStatusEnum;
import com.ruoyi.system.mapper.TPhysicalGoodsMapper;
import com.ruoyi.system.mapper.TPhysicalGoodsOrderMapper;
import com.ruoyi.system.model.TCompany;
import com.ruoyi.system.model.TPhysicalGoods;
import com.ruoyi.system.model.TPhysicalGoodsOrder;
import com.ruoyi.system.query.BigGiftPackageQuery;
import com.ruoyi.system.service.TAppUserService;
import com.ruoyi.system.service.TPhysicalGoodsOrderService;
import com.ruoyi.system.utils.ICBCPayUtil;
import com.ruoyi.system.utils.OrderCodeGenerator;
import com.ruoyi.system.vo.PlaceOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
 
/**
 * <p>
 * 实物商品订单 服务实现类
 * </p>
 *
 * @author xiaochen
 * @since 2025-12-08
 */
@Slf4j
@Service
public class TPhysicalGoodsOrderServiceImpl extends ServiceImpl<TPhysicalGoodsOrderMapper, TPhysicalGoodsOrder> implements TPhysicalGoodsOrderService {
 
    @Resource
    private TPhysicalGoodsMapper physicalGoodsMapper;
 
    @Resource
    private ICBCPayUtil icbcPayUtil;
 
    @Autowired
    private ICBCConfig icbcConfig;
 
    @Autowired
    private RedisTemplate redisTemplate;
 
    @Autowired
    private TAppUserService appUserService;
 
    /**
     * 实物商品支付参数 Redis Key 前缀
     */
    private static final String PHYSICAL_ORDER_PAY_PARAMS_KEY = "physical_order_pay_params:";
 
    /**
     * 支付参数缓存过期时间(24小时)
     */
    private static final long PAY_PARAMS_EXPIRE_HOURS = 60;
 
    @Override
    public Page<TPhysicalGoodsOrder> pageList(BigGiftPackageQuery query) {
        Page<TPhysicalGoodsOrder> page = new Page<>(query.getPageNum(), query.getPageSize());
        Page<TPhysicalGoodsOrder> tPhysicalGoodsOrderPage = this.baseMapper.pageList(page, query);
        tPhysicalGoodsOrderPage.getRecords().forEach(order -> {
 
            order.setPhysicalGoodsName(JSONObject.parseObject(order.getPhysicalGoods()).getString("name"));
        });
        return tPhysicalGoodsOrderPage;
    }
 
    @Override
    public List<TPhysicalGoodsOrder> export(BigGiftPackageQuery query) {
        List<TPhysicalGoodsOrder> export = this.baseMapper.export(query);
        export.forEach(order -> {
            order.setPhysicalGoodsName(JSONObject.parseObject(order.getPhysicalGoods()).getString("name"));
        });
        return export;
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlaceOrderVO placeOrder(PhysicalGoodsPlaceOrderDTO dto, Integer appUserId, String openid) {
        // 1. 校验商品是否存在
        TPhysicalGoods physicalGoods = physicalGoodsMapper.selectById(dto.getPhysicalGoodsId());
        if (physicalGoods == null) {
            throw new ServiceException("商品不存在");
        }
 
        // 2. 创建订单
        TPhysicalGoodsOrder order = new TPhysicalGoodsOrder();
        String orderCode = OrderCodeGenerator.generatePhysicalGoodsOrderCode();
        order.setCode(orderCode);
        order.setAppUserId(appUserId);
        order.setCreateTime(LocalDateTime.now());
        order.setPhysicalGoodsId(dto.getPhysicalGoodsId());
        order.setPhysicalGoods(JSON.toJSONString(physicalGoods));
        order.setOrderPrice(physicalGoods.getTotalPrice());
        order.setPaymentPrice(physicalGoods.getTotalPrice());
        // 支付方式:1=微信
        order.setPaymentMethod(1);
        // 订单状态:1=待付款
        order.setStatus(PhysicalGoodsOrderStatusEnum.PENDING_PAYMENT.getCode());
        order.setDelFlag(0);
 
        //查询用户所属公司,获取经销商商户号
        TCompany company = appUserService.getUserCompany(appUserId);
        order.setCompanyId(company.getId());
        this.save(order);
 
        // 3. 更新商品销量
        Integer currentSales = physicalGoods.getSales() == null ? 0 : physicalGoods.getSales();
        physicalGoods.setSales(currentSales + 1);
        physicalGoodsMapper.updateById(physicalGoods);
        // 4. 调用工行支付
        log.info("实物商品下单,订单号:{},支付金额:{},用户ID:{}", orderCode, physicalGoods.getTotalPrice(), appUserId);
        JSONObject paymentParams = icbcPayUtil.wechatPay(orderCode, physicalGoods.getTotalPrice(), physicalGoods.getName(),
                openid,icbcConfig.getNotifyUrl()+"/physical/pay-notify", company.getMerchantNumber(), company.getMerchantOpenid());
 
        // 5. 缓存支付参数到 Redis(用于立即支付)
        String redisKey = PHYSICAL_ORDER_PAY_PARAMS_KEY + order.getId();
        redisTemplate.opsForValue().set(redisKey, paymentParams.toJSONString(), PAY_PARAMS_EXPIRE_HOURS, TimeUnit.MINUTES);
        log.info("实物商品支付参数已缓存,订单ID:{},Redis Key:{}", order.getId(), redisKey);
 
        // 6. 构建返回结果
        PlaceOrderVO vo = new PlaceOrderVO();
        vo.setOrderIds(Collections.singletonList(order.getId()));
        vo.setOrderCodes(Collections.singletonList(orderCode));
        vo.setPaymentParams(paymentParams);
        return vo;
    }
 
    @Override
    public PlaceOrderVO payNow(Integer orderId, Integer appUserId) {
        // 1. 查询订单
        TPhysicalGoodsOrder order = this.getById(orderId);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
 
        // 2. 校验订单所属用户
        if (!order.getAppUserId().equals(appUserId)) {
            throw new ServiceException("无权操作此订单");
        }
 
        // 3. 校验订单状态(必须是待付款)
        if (!PhysicalGoodsOrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) {
            throw new ServiceException("订单状态不正确,无法支付");
        }
 
        // 4. 从 Redis 获取缓存的支付参数
        String redisKey = PHYSICAL_ORDER_PAY_PARAMS_KEY + orderId;
        Object cachedParams = redisTemplate.opsForValue().get(redisKey);
        if (cachedParams == null) {
            throw new ServiceException("支付参数已过期,请重新下单");
        }
 
        // 5. 构建返回结果
        PlaceOrderVO vo = new PlaceOrderVO();
        vo.setOrderIds(Collections.singletonList(order.getId()));
        vo.setOrderCodes(Collections.singletonList(order.getCode()));
        vo.setPaymentParams(JSON.parseObject(cachedParams.toString()));
 
        log.info("实物商品立即支付,订单ID:{},用户ID:{}", orderId, appUserId);
        return vo;
    }
}