基于mall4j产品的二开项目后端
lee
2024-12-18 efdb99f8cecc4afb592afad79c761081d5d5cf22
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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许,不可做商业用途!
 *
 * 版权所有,侵权必究!
 */
package com.yami.shop.api.controller;
 
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.yami.shop.bean.app.dto.*;
import com.yami.shop.bean.app.param.OrderParam;
import com.yami.shop.bean.app.param.OrderPayInfoParam;
import com.yami.shop.bean.app.param.SubmitOrderParam;
import com.yami.shop.bean.enums.*;
import com.yami.shop.bean.event.EsProductUpdateEvent;
import com.yami.shop.bean.event.SubmitSeckillOrderEvent;
import com.yami.shop.bean.model.Order;
import com.yami.shop.bean.model.OrderItem;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.UserAddrOrder;
import com.yami.shop.bean.param.ChooseCouponParam;
import com.yami.shop.bean.param.PlatformChooseCouponParam;
import com.yami.shop.bean.vo.UserDeliveryInfoVO;
import com.yami.shop.common.bean.ContranctInfo;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.response.ResponseEnum;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.Arith;
import com.yami.shop.delivery.api.manager.DeliveryOrderManager;
import com.yami.shop.manager.*;
import com.yami.shop.manager.impl.ConfirmOrderManager;
import com.yami.shop.manager.impl.ShopCartAdapter;
import com.yami.shop.manager.impl.ShopCartItemAdapter;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.service.*;
import com.yami.shop.service.ShopCustomerService;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.*;
 
import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
 
/**
 * @author LGH
 */
@Slf4j
@RestController
@RequestMapping("/p/order")
@Tag(name = "订单接口")
public class OrderController {
 
    @Autowired
    private OrderService orderService;
    @Autowired
    private SubmitOrderManager submitOrderManager;
    @Autowired
    private SkuService skuService;
    @Autowired
    private ProductService productService;
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private UserAddrOrderService userAddrOrderService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    @Autowired
    private ShopCartAdapter shopCartAdapter;
    @Autowired
    private ShopCartItemAdapter shopCartItemAdapter;
    @Autowired
    private ConfirmOrderManager confirmOrderManager;
    @Autowired
    private ThreadPoolExecutor orderThreadPoolExecutor;
    @Autowired
    private DeliveryOrderManager deliveryOrderManager;
    @Autowired
    private DiscountShopCartManager discountShopCartManager;
    @Autowired
    private ComboShopCartManager comboShopCartManager;
    @Autowired
    private CouponConfirmOrderManager couponConfirmOrderManager;
    @Autowired
    private UserLevelOrderManager userLevelOrderManager;
    @Autowired
    private OrderUseScoreManager orderUseScoreManager;
    @Autowired
    private ShopCustomerService shopCustomerService;
 
 
    @PostMapping("/confirm")
    @Operation(summary = "结算,生成普通订单信息", description = "传入下单所需要的参数进行下单")
    public ServerResponseEntity<ShopCartOrderMergerDto> confirm(@Valid @RequestBody OrderParam orderParam) throws ExecutionException, InterruptedException {
//        if(orderParam != null){
//            throw new YamiShopBindException("该功能暂未开放");
//        }
        String userId = SecurityUtils.getUser().getUserId();
        // 将要返回给前端的完整的订单信息
        ShopCartOrderMergerDto shopCartOrderMerger = new ShopCartOrderMergerDto();
        shopCartOrderMerger.setIsScorePay(orderParam.getIsScorePay());
        shopCartOrderMerger.setDvyType(orderParam.getDvyType());
        shopCartOrderMerger.setUsableScore(orderParam.getUserUseScore());
        shopCartOrderMerger.setInstallsWay(orderParam.getOrderItem().getInstallsWay());
        shopCartOrderMerger.setOrderType(OrderType.ORDINARY);
        // 组装获取用户提交的购物车商品项
        List<ShopCartItemDto> shopCartItemsDb = shopCartItemAdapter.getShopCartItemsByOrderItems(orderParam.getOrderItem(), userId, orderParam.getAddrId());
        // 筛选过滤掉不同配送的商品
        List<ShopCartItemDto> shopCartItems = confirmOrderManager.filterShopItemsByType(shopCartOrderMerger, shopCartItemsDb);
        // 该商品不满足任何的配送方式
        if (CollectionUtil.isEmpty(shopCartItems)) {
            return ServerResponseEntity.fail(ResponseEnum.ORDER_DELIVERY_NOT_SUPPORTED, shopCartOrderMerger);
        }
        ShopCartItemDto firstShopCartItem = shopCartItems.get(0);
        // 是否为预售订单
        orderParam.setPreSellStatus(firstShopCartItem.getPreSellStatus());
        shopCartOrderMerger.setPreSellStatus(firstShopCartItem.getPreSellStatus());
        // 商品类别 0.实物商品 1. 虚拟商品
        int mold = 0;
        if (shopCartItems.stream().filter(shopCartItemDto -> shopCartItemDto.getMold() == 1).count() == shopCartItems.size()) {
            // 订单项中的所有商品都为虚拟商品时,才是虚拟订单
            mold = 1;
        }
        shopCartOrderMerger.setMold(mold);
 
        // 购物车
        List<ShopCartDto> shopCarts = shopCartAdapter.getShopCarts(shopCartItems);
 
        // 计算满减,并重新组合购物车
        if (discountShopCartManager != null) {
            shopCarts = discountShopCartManager.calculateDiscountAndMakeUpShopCart(shopCarts);
        }
 
        // 计算套餐,并重新组合购物车
        if (comboShopCartManager != null) {
            shopCarts = comboShopCartManager.calculateDiscountAndMakeUpShopCart(shopCarts);
        }
 
        // 异步计算运费,运费暂时和优惠券没啥关联,可以与优惠券异步计算,获取用户地址,自提信息
        CompletableFuture<UserDeliveryInfoVO> deliveryFuture = null;
        if (Objects.equals(mold, 0)) {
            deliveryFuture = CompletableFuture.supplyAsync(
                    () -> deliveryOrderManager.calculateAndGetDeliverInfo(userId, orderParam.getAddrId(), orderParam.getDvyType(), shopCartItems),
                    orderThreadPoolExecutor);
        }
 
 
        // 计算优惠券,并返回优惠券信息
        if (couponConfirmOrderManager != null) {
            shopCarts = couponConfirmOrderManager.chooseShopCoupon(new ChooseCouponParam(orderParam.getUserChangeCoupon(), orderParam.getCouponUserIds(), shopCarts));
        }
 
        // 运费用异步计算,最后要等运费出结果
        UserDeliveryInfoVO userDeliveryInfo = new UserDeliveryInfoVO();
        if (Objects.nonNull(deliveryFuture)) {
            userDeliveryInfo = deliveryFuture.get();
        }
 
        // 当算完一遍店铺的各种满减活动时,重算一遍订单金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculateShop(shopCartOrderMerger, shopCarts, userDeliveryInfo);
 
        double orderShopReduce = shopCartOrderMerger.getOrderReduce();
 
        // ===============================================开始平台优惠的计算==================================================
 
        // 计算平台优惠券,并返回平台优惠券信息
        if (couponConfirmOrderManager != null) {
            shopCartOrderMerger = couponConfirmOrderManager.choosePlatformCoupon(new PlatformChooseCouponParam(orderParam.getUserChangeCoupon(), orderParam.getCouponUserIds(), shopCartOrderMerger));
        }
 
        // 等级折扣
        if (userLevelOrderManager != null) {
            userLevelOrderManager.calculateLevelDiscount(shopCartOrderMerger);
        }
 
        // ===============================================结束平台优惠的计算==================================================
        // 结束平台优惠的计算之后,还要重算一遍金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculatePlatform(shopCartOrderMerger);
 
        // 计算订单积分抵扣金额
        if (orderUseScoreManager != null) {
            orderUseScoreManager.orderUseScore(shopCartOrderMerger, orderParam, shopCartItems);
        }
        shopCartOrderMerger.setOrderShopReduce(orderShopReduce);
        // 计算平台佣金
        confirmOrderManager.calculatePlatformCommission(shopCartOrderMerger);
 
        // 缓存计算
        confirmOrderManager.cacheCalculatedInfo(userId, shopCartOrderMerger);
        return ServerResponseEntity.success(shopCartOrderMerger);
    }
 
    @PostMapping("/submit")
    @Operation(summary = "提交订单,返回支付流水号", description = "根据传入的参数判断是否为购物车提交订单,同时对购物车进行删除,用户开始进行支付,根据店铺进行拆单")
    public ServerResponseEntity<OrderNumbersDto> submitOrders(@Valid @RequestBody SubmitOrderParam submitOrderParam) {
        String userId = SecurityUtils.getUser().getUserId();
        ServerResponseEntity<ShopCartOrderMergerDto> orderCheckResult = submitOrderManager.checkSubmitInfo(submitOrderParam, userId);
        if (!orderCheckResult.isSuccess()) {
            if (StrUtil.equals(ResponseEnum.REPEAT_ORDER.value(), orderCheckResult.getCode())) {
                OrderNumbersDto orderNumbersDto = new OrderNumbersDto(null);
                orderNumbersDto.setDuplicateError(1);
                return ServerResponseEntity.success(orderNumbersDto);
            }
        }
        ShopCartOrderMergerDto mergerOrder = orderCheckResult.getData();
 
        List<ShopCartOrderDto> shopCartOrders = mergerOrder.getShopCartOrders();
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {
            List<ShopCartItemDiscountDto> shopCartItemDiscounts = shopCartOrder.getShopCartItemDiscounts();
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemDto> shopCartItems = shopCartItemDiscount.getShopCartItems();
                for (ShopCartItemDto shopCartItem : shopCartItems) {
                    Long prodId = shopCartItem.getProdId();
                    Product productById = productService.getProductById(prodId);
                    if (!productById.getStatus().equals(ProdStatusEnums.NORMAL.getValue())) {
                        throw new YamiShopBindException("商品:[" + productById.getProdName() + "]已下架");
                    }
                }
            }
        }
        List<Order> orders = orderService.submit(mergerOrder);
        StringBuilder orderNumbers = new StringBuilder();
        Set<Long> prodIds = new HashSet<>();
        List<Long> ItemIds = new ArrayList<>();
        for (Order order : orders) {
            orderNumbers.append(order.getOrderNumber()).append(StrUtil.COMMA);
            prodIds.addAll(order.getOrderItems().stream().map(OrderItem::getProdId).collect(Collectors.toSet()));
            ItemIds.addAll(order.getOrderItems().stream().map(OrderItem::getOrderItemId).collect(Collectors.toList()));
        }
        orderNumbers.deleteCharAt(orderNumbers.length() - 1);
        // 店铺客户创建
        shopCustomerService.saveCustomerByOrders(orders);
 
        // 移除缓存
        for (ShopCartOrderDto shopCartOrder : shopCartOrders) {
            for (ShopCartItemDiscountDto shopCartItemDiscount : shopCartOrder.getShopCartItemDiscounts()) {
                for (ShopCartItemDto shopCartItem : shopCartItemDiscount.getShopCartItems()) {
                    skuService.removeSkuCacheBySkuId(shopCartItem.getSkuId(), shopCartItem.getProdId());
                    productService.removeProdCacheByProdId(shopCartItem.getProdId());
                }
            }
        }
        orderService.removeConfirmOrderCache(userId + submitOrderParam.getUuid());
        // 更新es中的商品库存--更新失败打印日志,优先保证订单流程没问题
        try {
            eventPublisher.publishEvent(new EsProductUpdateEvent(mergerOrder.getProdList(), EsOperationType.UPDATE_ORDER_STOCK_NUM_BATCH));
        } catch (Exception e) {
            log.error("提交订单-更新es商品库存失败,错误为:{}", e);
        }
 
        OrderNumbersDto orderNumbersDto = new OrderNumbersDto(orderNumbers.toString());
        orderNumbersDto.setOrderItemIds(ItemIds);
        return ServerResponseEntity.success(orderNumbersDto);
    }
 
 
    @GetMapping("/getOrderPayInfoByOrderNumber")
    @Operation(summary = "获取订单支付信息", description = "获取订单支付的商品/地址信息")
    @Parameter(name = "orderNumbers", description = "订单流水号", required = true)
    public ServerResponseEntity<OrderPayInfoParam> getOrderPayInfoByOrderNumber(@RequestParam("orderNumbers") String orderNumbers) {
        String userId = SecurityUtils.getUser().getUserId();
        List<String> orderNumberList = Arrays.asList(orderNumbers.split(StrUtil.COMMA));
        //获取订单信息
        List<Order> orderList = orderService.getOrderPayInfoByOrderNumber(orderNumberList);
        List<String> prodNameList = Lists.newArrayList();
        Long addrOrderId = null;
        Date endTime = null;
        int totalScore = 0;
        double totalFee = 0.0;
        boolean isStation = false;
        boolean hasAddr = false;
        Integer status = 1;
        Order orderDb = new Order();
        //获取商品名集合
        for (Order order : orderList) {
            if (!Objects.equals(userId, order.getUserId())) {
                throw new YamiShopBindException("yami.order.no.exist");
            }
            for (OrderItem orderItem : order.getOrderItems()) {
                prodNameList.add(orderItem.getProdName());
                totalScore += orderItem.getUseScore() != null ? orderItem.getUseScore() : 0;
            }
            //第一次循环,获取订单地址id,订单过期时间
            if (Objects.isNull(addrOrderId)) {
                addrOrderId = order.getAddrOrderId();
                if (Objects.equals(2, order.getOrderType())) {
                    // 获取秒杀订单的取消订单时间
                    Integer maxCancelTime = 0;
                    SubmitSeckillOrderEvent event = new SubmitSeckillOrderEvent(order, maxCancelTime);
                    applicationContext.publishEvent(event);
                    maxCancelTime = event.getMaxCancelTime();
                    if (maxCancelTime <= 0) {
                        maxCancelTime = 30;
                    }
                    endTime = DateUtil.offsetMinute(order.getCreateTime(), maxCancelTime);
                } else {
                    endTime = DateUtil.offsetMinute(order.getCreateTime(), 30);
                }
            }
            totalFee = Arith.add(totalFee, order.getActualTotal());
            if (Objects.equals(order.getDvyType(), DvyType.STATION.value())) {
                isStation = true;
                orderDb = order;
            }
            if (!Objects.equals(order.getStatus(), OrderStatus.UNPAY.value())) {
                status = order.getStatus();
            }
            if (!hasAddr && !Objects.equals(order.getOrderMold(), 1)) {
                addrOrderId = order.getAddrOrderId();
                hasAddr = true;
            }
        }
        OrderPayInfoParam orderPayInfoParam = new OrderPayInfoParam();
        orderPayInfoParam.setStatus(status);
        orderPayInfoParam.setProdNameList(prodNameList);
        orderPayInfoParam.setEndTime(endTime);
        orderPayInfoParam.setTotalFee(totalFee);
        orderPayInfoParam.setTotalScore(totalScore);
        if (isStation) {
            orderPayInfoParam.setUserAddr("");
            orderPayInfoParam.setReceiver(orderDb.getReceiverName());
            orderPayInfoParam.setMobile(orderDb.getReceiverMobile());
        } else if (hasAddr) {
            //写入商品名、收货地址/电话
            UserAddrOrder userAddrOrder = userAddrOrderService.getById(addrOrderId);
            String addr = userAddrOrder.getProvince() + userAddrOrder.getCity() + userAddrOrder.getArea() + userAddrOrder.getAddr();
            orderPayInfoParam.setUserAddr(addr);
            orderPayInfoParam.setReceiver(userAddrOrder.getReceiver());
            orderPayInfoParam.setMobile(userAddrOrder.getMobile());
        }
        return ServerResponseEntity.success(orderPayInfoParam);
    }
 
    @PostMapping("/convertShopMall")
    @Operation(summary = "转换商城合同" , description = "转换商城合同")
    public ServerResponseEntity<String> convertShopMall(@RequestBody ContranctInfo info) {
        String url = orderService.convertShopMall(info);
        if(!StringUtils.isEmpty(url)){
            return ServerResponseEntity.success(url);
        }else{
            return ServerResponseEntity.showFailMsg( ResponseEnum.ERROR.getMsg());
        }
    }
}