mitao
2024-09-09 cf98926793932b132000e237a487ba4343084410
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
package com.xinquan.order.service.impl;
 
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinquan.common.core.constant.Constants;
import com.xinquan.common.core.constant.SecurityConstants;
import com.xinquan.common.core.enums.ChargeTypeEnum;
import com.xinquan.common.core.enums.DisabledEnum;
import com.xinquan.common.core.enums.PaymentStatusEnum;
import com.xinquan.common.core.enums.PaymentTypeEnum;
import com.xinquan.common.core.exception.ServiceException;
import com.xinquan.common.core.utils.ip.IpUtils;
import com.xinquan.common.security.utils.SecurityUtils;
import com.xinquan.course.api.domain.Course;
import com.xinquan.course.api.feign.RemoteCourseService;
import com.xinquan.meditation.api.domain.Meditation;
import com.xinquan.meditation.api.feign.RemoteMeditationService;
import com.xinquan.order.api.domain.Order;
import com.xinquan.order.domain.OrderPaymentRecord;
import com.xinquan.order.domain.vo.ClientPlaceOrderVO;
import com.xinquan.order.mapper.OrderMapper;
import com.xinquan.order.service.OrderPaymentRecordService;
import com.xinquan.order.service.OrderService;
import com.xinquan.order.utils.JuHeFuUtil;
import com.xinquan.order.utils.OrderUtil;
import com.xinquan.user.api.domain.AppUser;
import com.xinquan.user.api.domain.dto.AppUserDTO;
import com.xinquan.user.api.feign.RemoteAppUserService;
import java.math.BigDecimal;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author mitao
 * @since 2024-08-21
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
 
    private final RemoteMeditationService remoteMeditationService;
    private final RemoteCourseService remoteCourseService;
    private final RemoteAppUserService remoteAppUserService;
    private final OrderPaymentRecordService orderPaymentRecordService;
 
    /**
     * 创建待支付订单
     *
     * @param targetId    目标id
     * @param orderFrom   订单来源 1=冥想音频 2=课程
     * @param receiverId  被赠送课程APP用户id
     * @param balanceFlag 是否使用余额抵扣 1=是 2=否
     * @param payType     支付方式 1=微信 2=支付宝
     * @return 下单返回数据视图对象
     * @see com.xinquan.order.domain.vo.ClientPlaceOrderVO
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClientPlaceOrderVO placeOrder(Long targetId, Integer orderFrom, Long receiverId,
            Integer balanceFlag, Integer payType) throws Exception {
        // 获取当前登录用户id
        Long userId = SecurityUtils.getUserId();
        // 获取用户信息
        AppUser appUser = getAppUserById(userId);
        ClientPlaceOrderVO clientPlaceOrderVO = new ClientPlaceOrderVO();
        Order order = new Order();
        // 购买冥想音频
        if (orderFrom == 1) {
            Meditation meditation = remoteMeditationService.getMeditationById(targetId,
                    SecurityConstants.INNER).getData();
            String meditationTitle = meditation.getMeditationTitle();
            String detailDescription = meditation.getDetailDescription();
            String wxOpenId = appUser.getWxOpenId();
            // 创建订单
            String orderNo = OrderUtil.getOrderNoForPrefix("MX");
            order.setOrderFrom(orderFrom);
            order.setBizOrderNo(orderNo);
            order.setBusinessId(meditation.getId());
            order.setAppUserId(userId);
            order.setTotalAmount(meditation.getGeneralPrice());
            this.save(order);
            Long orderId = order.getId();
            clientPlaceOrderVO.setOrderNo(orderNo);
            clientPlaceOrderVO.setId(orderId);
            // 如果冥想音频价格设定为单独收费,且需要使用余额抵扣
            if (balanceFlag.equals(1) && meditation.getChargeType()
                    .equals(ChargeTypeEnum.SEPARATE_CHARGE.getCode())) {
                BigDecimal needPayAmount = handleBalancePayment(appUser,
                        meditation.getGeneralPrice(),
                        orderId);
 
                if (needPayAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    clientPlaceOrderVO.setZeroFlag(DisabledEnum.YES.getCode());
                    return clientPlaceOrderVO;
                }
                // 创建支付订单
                createPayment(payType, orderNo, needPayAmount, meditationTitle, detailDescription,
                        wxOpenId, orderId, clientPlaceOrderVO);
            } else {
                // 创建支付订单
                createPayment(payType, orderNo, meditation.getGeneralPrice(), meditationTitle,
                        detailDescription, wxOpenId, orderId, clientPlaceOrderVO);
            }
        } else {
            // 购买课程
            Course course = remoteCourseService.getCourseById(targetId,
                    SecurityConstants.INNER).getData();
            String courseTitle = course.getCourseTitle();
            String wxOpenId = appUser.getWxOpenId();
            String description = course.getDescription();
 
            // 创建订单
            String orderNo = OrderUtil.getOrderNoForPrefix("KC");
            order.setOrderFrom(orderFrom);
            order.setBizOrderNo(orderNo);
            order.setBusinessId(course.getId());
            order.setAppUserId(userId);
            order.setTotalAmount(course.getGeneralPrice());
            this.save(order);
            Long orderId = order.getId();
            clientPlaceOrderVO.setOrderNo(orderNo);
            clientPlaceOrderVO.setId(orderId);
 
            if (balanceFlag.equals(1) && course.getChargeType()
                    .equals(ChargeTypeEnum.SEPARATE_CHARGE.getCode())) {
                BigDecimal needPayAmount = handleBalancePayment(appUser, course.getGeneralPrice(),
                        orderId);
 
                if (needPayAmount.compareTo(BigDecimal.ZERO) <= 0) {
                    clientPlaceOrderVO.setZeroFlag(DisabledEnum.YES.getCode());
                    return clientPlaceOrderVO;
                }
                // 创建支付订单
                createPayment(payType, orderNo, needPayAmount, courseTitle, description,
                        wxOpenId, orderId, clientPlaceOrderVO);
            } else {
                // 创建支付订单
                createPayment(payType, orderNo, course.getGeneralPrice(), courseTitle,
                        description, wxOpenId, orderId, clientPlaceOrderVO);
            }
        }
        return clientPlaceOrderVO;
    }
 
    /**
     * 处理余额抵扣
     *
     * @param appUser      app用户
     * @param generalPrice 通用价格
     * @param orderId      订单号
     * @return 需要支付的金额
     */
    @NotNull
    private BigDecimal handleBalancePayment(AppUser appUser, BigDecimal generalPrice,
            Long orderId) {
        if (appUser.getBalance().compareTo(BigDecimal.ZERO) < 0) {
            throw new ServiceException("用户可用余额不足,请重新选择支付方案");
        }
        // 更新用户余额
        remoteAppUserService.updateAppUser(
                AppUserDTO.builder().balance(
                                appUser.getBalance().subtract(generalPrice))
                        .build(), SecurityConstants.INNER);
 
        OrderPaymentRecord balancePaymentRecord = new OrderPaymentRecord();
        balancePaymentRecord.setOrderId(orderId);
        balancePaymentRecord.setPaymentType(PaymentTypeEnum.BALANCE_PAY.getCode());
        balancePaymentRecord.setPaymentStatus(PaymentStatusEnum.COMPLETED.getCode());
        orderPaymentRecordService.save(balancePaymentRecord);
 
        // 计算除去余额还需支付的金额
        return generalPrice
                .subtract(appUser.getBalance());
    }
 
    /**
     * 获取登录用户信息
     *
     * @param userId APP用户id
     * @return AppUser
     */
    private AppUser getAppUserById(Long userId) {
        return remoteAppUserService.getUserByCondition(
                AppUserDTO.builder().id(userId).build(),
                SecurityConstants.INNER).getData();
    }
 
    /**
     * 创建支付订单
     *
     * @param payType            支付方式 1=微信 2=支付宝
     * @param orderNo            订单编号
     * @param needPayAmount      支付金额
     * @param goodsTitle         商品标题
     * @param goodsDesc          商品描述
     * @param wxOpenId           微信openId
     * @param orderId            订单id
     * @param clientPlaceOrderVO 下单返回数据视图对象
     * @throws Exception
     */
    private void createPayment(Integer payType, String orderNo, BigDecimal needPayAmount,
            String goodsTitle, String goodsDesc, String wxOpenId, Long orderId,
            ClientPlaceOrderVO clientPlaceOrderVO) throws Exception {
        // 截取前42个字符 商品描述信息,微信小程序和微信公众号该字段,最大长度 42 个字符
        goodsDesc = goodsDesc.substring(0, 42);
        // 调用第三方支付获取支付信息
        JSONObject payInfo = JuHeFuUtil.createPayment(orderNo, payType,
                needPayAmount.toString(), goodsTitle, goodsDesc,
                IpUtils.getIpAddr(), wxOpenId, Constants.PAYMENT_NOTIFY_URL);
        // 第三方支付记录
        OrderPaymentRecord paymentRecord = new OrderPaymentRecord();
        paymentRecord.setOrderId(orderId);
 
        if (payType == 1) {
            clientPlaceOrderVO.setPayInfo(payInfo.getString("pay_info"));
            paymentRecord.setPaymentType(PaymentTypeEnum.WECHAT_PAY.getCode());
        } else {
            clientPlaceOrderVO.setQrcodeUrl(payInfo.getString("qrcode_url"));
            paymentRecord.setPaymentType(PaymentTypeEnum.ALI_PAY.getCode());
        }
 
        paymentRecord.setPaymentStatus(PaymentStatusEnum.TO_BE_PAID.getCode());
        orderPaymentRecordService.save(paymentRecord);
        // 设置订单是否需要支付标识
        clientPlaceOrderVO.setZeroFlag(DisabledEnum.NO.getCode());
    }
 
    /**
     * 根据类型获取已完成的订单列表
     *
     * @param userId    用户id
     * @param orderFrom 订单来源
     * @return
     */
    @Override
    public List<Order> getOrderListByType(Long userId, Integer orderFrom) {
        return this.lambdaQuery().eq(Order::getAppUserId, userId).eq(Order::getOrderFrom, orderFrom)
                .eq(Order::getPaymentStatus, PaymentStatusEnum.COMPLETED.getCode()).list();
    }
}