1. 提交订单

在结算页我们可以看到我们要购买的物品,价格,收货地址等,如果确认无误,我们就需要提交订单了,因为我们的商城是多商户系统,用户在购买商品的时候可能从多家店铺购买,所以订单需要区分主单和子单。

image-20220105175341946

1.1 先改一个bug

之前我们在查询商品信息详情的接口:buyer/goods/sku/{goodsId}/{skuId}中,其中GoodsSkuVO的id就是skuid,我们之前使用的是long类型,由于精度损失问题,前端在接收分布式id,长整型的时候会变成另外的数字,导致加入购物车会出现问题,所以这里我们先要改掉这个bug

@Data
public class GoodsSkuVO implements Serializable {


    private String id;
}
1
2
3
4
5
6

在获取的地方,copy属性的时候,long是不能copy到string的所以需要手动赋值一下

 public GoodsSkuVO getGoodsSkuVO(GoodsSku goodsSku) {

        GoodsSkuVO goodsSkuVO = new GoodsSkuVO();
        BeanUtils.copyProperties(goodsSku, goodsSkuVO);
        goodsSkuVO.setId(goodsSku.getId().toString());
        //获取sku信息
1
2
3
4
5
6

1.2 修改之前的逻辑

之前创建购物车的时候,调用dubbo服务的时候,传入的是userId,现在我们将AuthUser对象传入

public TradeVo createTradeVo(CartTypeEnum cartTypeEnum, AuthUser authUser) {
        //把购物车数据 是放入缓存的,先从缓存拿
        TradeVo tradeVo = cacheService.get(CartTypeEnum.CART.name()+"_"+authUser.getId(), TradeVo.class);
        if (tradeVo == null){
            tradeVo = new TradeVo();
            tradeVo.init(cartTypeEnum);
            tradeVo.setMemberId(authUser.getId());
            tradeVo.setMemberName(authUser.getUsername());
            //TODO 根据用户id查询用户的收货地址,便于订单进行判断

        }
        return tradeVo;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13

1.3 接口说明

接口路径:/buyer/trade/carts/create/trade

参数:

package com.mszlu.shop.model.buyer.params;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;
import java.util.List;

/**
 * 交易参数
 **/
@Data
public class TradeParams implements Serializable {


    @ApiModelProperty(value = "购物车购买:CART/立即购买:BUY_NOW/拼团购买:PINTUAN / 积分购买:POINT")
    private String way;

    /**
     * @see com.mszlu.shop.model.buyer.eums.ClientType
     */
    @ApiModelProperty(value = "客户端:H5/移动端 PC/PC端,WECHAT_MP/小程序端,APP/移动应用端")
    private String client;

    @ApiModelProperty(value = "店铺备注")
    private List<StoreRemarkParam> remark;

    @ApiModelProperty(value = "是否为其他订单下的订单,如果是则为依赖订单的sn,否则为空")
    private String parentOrderSn;


}

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
package com.mszlu.shop.model.buyer.params;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * 店铺备注
 */
@Data
public class StoreRemarkParam implements Serializable {

    @ApiModelProperty(value = "店铺id")
    private String storeId;

    @ApiModelProperty(value = "备注")
    private String remark;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

例子:

{
  "client": "PC",
  "way": "CART"
}
1
2
3
4

返回数据:

{
    "success":true,
    "message":"success",
    "code":2000000000,
    "result":{
        "sn":"T202201061479001772897861632",
        "memberId":"1",
        "memberName":"mszlu",
        "paymentMethod":null,
        "payStatus":"UNPAID",
        "flowPrice":29,
        "goodsPrice":29,
        "freightPrice":0,
        "discountPrice":0,
        "deliveryMethod":null,
        "consigneeName":"地址3",
        "consigneeMobile":"13011111111",
        "consigneeAddressPath":"北京市,北京城区,朝阳区,豆各庄镇",
        "consigneeAddressIdPath":"1371783043718578711,1371783043718578712,1371783043718578809,1371783043718578828"
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.mszlu.shop.model.buyer.vo.trade;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;

/**
 * 商品交易视图
 */
@Data
public class GoodsTradeVo implements Serializable {

        @ApiModelProperty(value = "交易编号")
        private String sn;

        @ApiModelProperty(value = "买家id")
        private String memberId;

        @ApiModelProperty(value = "买家用户名")
        private String memberName;

        @ApiModelProperty(value = "支付方式")
        private String paymentMethod;

        /**
         * @see com.mszlu.shop.model.buyer.eums.trade.PayStatusEnum
         */
        @ApiModelProperty(value = "付款状态")
        private String payStatus;

        @ApiModelProperty(value = "总价格")
        private Double flowPrice;

        @ApiModelProperty(value = "原价")
        private Double goodsPrice;

        @ApiModelProperty(value = "运费")
        private Double freightPrice;

        @ApiModelProperty(value = "优惠的金额")
        private Double discountPrice;

        /**
         * @see com.mszlu.shop.model.buyer.eums.trade.DeliveryMethodEnum
         */
        @ApiModelProperty(value = "配送方式")
        private String deliveryMethod;

        @ApiModelProperty(value = "收货人姓名")
        private String consigneeName;

        @ApiModelProperty(value = "收件人手机")
        private String consigneeMobile;

        @ApiModelProperty(value = "地址名称, ','分割")
        private String consigneeAddressPath;

        @ApiModelProperty(value = "地址id,','分割 ")
        private String consigneeAddressIdPath;
}

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

1.4 数据库设计

交易:ms_trade表image-20220105211442981

package com.mszlu.shop.model.buyer.pojo.trade;

import com.mszlu.shop.model.buyer.pojo.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;


/**
 * 交易
 */
@Data
@ApiModel(value = "交易")
public class Trade extends BaseEntity implements Serializable{

    private Long id;

    @ApiModelProperty(value = "交易编号")
    private String sn;

    @ApiModelProperty(value = "买家id")
    private String memberId;

    @ApiModelProperty(value = "买家用户名")
    private String memberName;

    @ApiModelProperty(value = "支付方式")
    private String paymentMethod;

    /**
     * @see com.mszlu.shop.model.buyer.eums.trade.PayStatusEnum
     */
    @ApiModelProperty(value = "付款状态")
    private String payStatus;

    @ApiModelProperty(value = "总价格")
    private Double flowPrice;

    @ApiModelProperty(value = "原价")
    private Double goodsPrice;

    @ApiModelProperty(value = "运费")
    private Double freightPrice;

    @ApiModelProperty(value = "优惠的金额")
    private Double discountPrice;

    /**
     * @see com.mszlu.shop.model.buyer.eums.trade.DeliveryMethodEnum
     */
    @ApiModelProperty(value = "配送方式")
    private String deliveryMethod;

    @ApiModelProperty(value = "收货人姓名")
    private String consigneeName;

    @ApiModelProperty(value = "收件人手机")
    private String consigneeMobile;

    @ApiModelProperty(value = "地址名称, ','分割")
    private String consigneeAddressPath;

    @ApiModelProperty(value = "地址id,','分割 ")
    private String consigneeAddressIdPath;

}
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
package com.mszlu.shop.model.buyer.eums.trade;

/**
 * 订单状态枚举
 */
public enum PayStatusEnum {

    /**
     * 支付状态
     */
    UNPAID("待付款"),
    PAID("已付款"),
    CANCEL("已取消");

    private final String description;

    PayStatusEnum(String description) {
        this.description = description;
    }

    public String description() {
        return this.description;
    }


}

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
package com.mszlu.shop.model.buyer.eums.trade;

/**
 * 配送方式
 **/
public enum DeliveryMethodEnum {

    /**
     * "自提"
     */
    SELF_PICK_UP("自提"),
    /**
     * "同城配送"
     */
    LOCAL_TOWN_DELIVERY("同城配送"),
    /**
     * "物流"
     */
    LOGISTICS("物流");

    private final String description;

    DeliveryMethodEnum(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

}

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

1.5 编码

1.5.1 Controller

 @ApiOperation(value = "创建交易")
    @PostMapping(value = "/create/trade")
    public Result<GoodsTradeVo> crateTrade(@RequestBody TradeParams tradeParams) {
        return this.buyerCartService.createTrade(tradeParams);
    }
1
2
3
4
5

1.5.2 Service

public Result<GoodsTradeVo> createTrade(TradeParams tradeParams) {
        AuthUser currentUser = UserContext.getCurrentUser();
        return cartService.createTrade(tradeParams,currentUser);
    }
1
2
3
4

1.5.3 dubbo服务

/**
     * 创建交易
     * @param tradeParams
     * @param authUser
     * @return
     */
    Result<GoodsTradeVo> createTrade(TradeParams tradeParams, AuthUser currentUser);
1
2
3
4
5
6
7
 @Override
    public Result<GoodsTradeVo> createTrade(TradeParams tradeParams, AuthUser authUser) {
        //获取购物车
        CartTypeEnum cartTypeEnum = CartTypeEnum.valueOf(tradeParams.getWay());
        TradeVo tradeVo = this.createTradeVo(cartTypeEnum,authUser);
        //设置基础属性
        tradeVo.setClientType(tradeParams.getClient());
        tradeVo.setStoreRemark(tradeParams.getRemark());
        tradeVo.setParentOrderSn(tradeParams.getParentOrderSn());
        //订单无收货地址校验
        if (tradeVo.getMemberAddress() == null) {
            return Result.fail(-999,"无收货地址");
        }
        //将购物车信息写入缓存,后续逻辑调用校验
        this.resetTradeVo(tradeVo,authUser);
        //构建交易
        //是否为单品渲染
        boolean isSingle = cartTypeEnum.equals(CartTypeEnum.PINTUAN) || cartTypeEnum.equals(CartTypeEnum.POINTS);
        if (isSingle){
            //根据不同的步骤 进行渲染
            tradeBuilder.renderCartBySteps(tradeVo, RenderStepStatement.singleTradeRender);
        }else{
            //
            tradeBuilder.renderCartBySteps(tradeVo, RenderStepStatement.tradeRender);
        }
        ////添加order订单及order_item子订单并返回
        Result<Trade> tradeResult = tradeService.createTrade(tradeVo,authUser);
        if (tradeResult.isSuccess()){
            this.cleanChecked(tradeVo,authUser);

            GoodsTradeVo goodsTradeVo = new GoodsTradeVo();
            BeanUtils.copyProperties(tradeResult.getResult(),goodsTradeVo);
            return Result.success(goodsTradeVo);
        }
        return Result.fail(tradeResult.getCode(),tradeResult.getMessage());
    }

    public void cleanChecked(TradeVo tradeVo,AuthUser authUser) {
        List<CartSkuVO> cartSkuVOS = tradeVo.getSkuList();
        List<CartSkuVO> deleteVos = new ArrayList<>();
        for (CartSkuVO cartSkuVO : cartSkuVOS) {
            if (Boolean.TRUE.equals(cartSkuVO.getChecked())) {
                deleteVos.add(cartSkuVO);
            }
        }
        cartSkuVOS.removeAll(deleteVos);
        //清除选择的优惠券
//        tradeVo.setPlatformCoupon(null);
//        tradeVo.setStoreCoupons(null);
        //清除添加过的备注
        tradeVo.setStoreRemark(null);
        String key = CartTypeEnum.CART.name()+"_"+authUser.getId();
        cacheService.set(key, tradeVo,null);
    }

    private void resetTradeVo(TradeVo tradeVo, AuthUser authUser) {
        String key = CartTypeEnum.CART.name()+"_"+authUser.getId();
        cacheService.set(key,tradeVo,null);
    }

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

为TradeVo添加店铺备注和收货地址的属性

 /**
     * 店铺备注
     */
    private List<StoreRemarkParam> storeRemark;

    private MemberAddressVo memberAddress;
1
2
3
4
5
6

在添加购物车的时候,将用户的默认地址设置进去

public TradeVo createTradeVo(CartTypeEnum cartTypeEnum, AuthUser authUser) {
        //把购物车数据 是放入缓存的,先从缓存拿
        TradeVo tradeVo = cacheService.get(CartTypeEnum.CART.name()+"_"+authUser.getId(), TradeVo.class);
        if (tradeVo == null){
            tradeVo = new TradeVo();
            tradeVo.init(cartTypeEnum);
            tradeVo.setMemberId(authUser.getId());
            tradeVo.setMemberName(authUser.getUsername());
            //TODO 根据用户id查询用户的收货地址,便于订单进行判断
            tradeVo.setMemberAddress(this.memberAddressService.findDefaultAddress(authUser.getId()));
        }
        return tradeVo;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
    public MemberAddressVo findDefaultAddress(String userId) {
        LambdaQueryWrapper<MemberAddress> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(MemberAddress::getMemberId,userId);
        queryWrapper.eq(MemberAddress::getIsDefault,true);
        queryWrapper.last("limit 1");
        MemberAddress memberAddress = memberAddressMapper.selectOne(queryWrapper);
        MemberAddressVo memberAddressVo = new MemberAddressVo();
        BeanUtils.copyProperties(memberAddress,memberAddressVo);
        return memberAddressVo;
    }
1
2
3
4
5
6
7
8
9
10
11
public void cleanChecked(TradeVo tradeVo,AuthUser authUser) {
        List<CartSkuVO> cartSkuVOS = tradeVo.getSkuList();
        List<CartSkuVO> deleteVos = new ArrayList<>();
        for (CartSkuVO cartSkuVO : cartSkuVOS) {
            if (Boolean.TRUE.equals(cartSkuVO.getChecked())) {
                deleteVos.add(cartSkuVO);
            }
        }
        cartSkuVOS.removeAll(deleteVos);
        //清除选择的优惠券
//        tradeVo.setPlatformCoupon(null);
//        tradeVo.setStoreCoupons(null);
        //清除添加过的备注
        tradeVo.setStoreRemark(null);
        String key = CartTypeEnum.CART.name()+"_"+authUser.getId();
        cacheService.set(key, tradeVo,null);
    }

    private void resetTradeVo(TradeVo tradeVo, AuthUser authUser) {
        String key = CartTypeEnum.CART.name()+"_"+authUser.getId();
        cacheService.set(key,tradeVo,null);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

添加order订单及order_item子订单并返回

package com.mszlu.shop.buyer.service;

import com.mszlu.shop.common.vo.Result;
import com.mszlu.shop.model.buyer.pojo.trade.Trade;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;

public interface TradeService {

    Result<Trade> createTrade(TradeVo tradeVo, AuthUser authUser);
}

1
2
3
4
5
6
7
8
9
10
11
package com.mszlu.shop.buyer.service.impl.trade;

import com.mszlu.shop.buyer.service.TradeService;
import com.mszlu.shop.model.buyer.pojo.trade.Trade;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import org.springframework.stereotype.Service;

@Service
public class TradeServiceImpl implements TradeService {
    @Override
    public Result<Trade> createTrade(TradeVo tradeVo, AuthUser authUser) {
        return null;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

1.6 交易处理

订单号生成:

之前渲染购物车的时候,我们并没有生成单号,现在我们需要在购物车添加的时候 生成对应的交易单号和订单号

package com.mszlu.shop.buyer.service.impl.trade.domain.render;

import com.mszlu.shop.buyer.service.impl.trade.domain.CartRenderStep;
import com.mszlu.shop.common.utils.SnowFlake;
import com.mszlu.shop.model.buyer.eums.RenderStepEnums;
import com.mszlu.shop.model.buyer.params.StoreRemarkParam;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;

/**
 * sn 生成
 */
@Order(7)
@Service
public class CartSnRender implements CartRenderStep {

    @Override
    public RenderStepEnums step() {
        return RenderStepEnums.CART_SN;
    }

    @Override
    public void render(TradeVo tradeVo) {
        //生成各个sn
        tradeVo.setSn(SnowFlake.createStr("T"));
        tradeVo.getCartList().forEach(item -> {
            //写入备注
            if (tradeVo.getStoreRemark() != null) {
                for (StoreRemarkParam remark : tradeVo.getStoreRemark()) {
                    if (item.getStoreId().equals(remark.getStoreId())) {
                        item.setRemark(remark.getRemark());
                    }
                }
            }
            item.setSn(SnowFlake.createStr("O"));
        });
    }
}

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

使用hutool工具包生成雪花id(分布式id算法):

导包

 <!-- Hutool工具包 -->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.5.8</version>
            </dependency>
1
2
3
4
5
6
package com.mszlu.shop.common.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;

/**
 * 雪花分布式id获取
 */
public class SnowFlake {

    /**
     * 机器id
     */
    private static long workerId = 0L;
    /**
     * 机房id
     */
    private static long datacenterId = 0L;

    private static Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);

    public static long getId() {
        return snowflake.nextId();
    }

    /**
     * 生成字符,带有前缀
     * @param prefix
     * @return
     */
    public static String createStr(String prefix) {
        return prefix + new DateTime().toString("yyyyMMdd") + SnowFlake.getId();
    }
    public static String getIdStr() {
        return snowflake.nextId() + "";
    }
}

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
package com.mszlu.shop.buyer.service.impl.trade;

import com.mszlu.shop.buyer.mapper.TradeMapper;
import com.mszlu.shop.buyer.service.OrderService;
import com.mszlu.shop.buyer.service.impl.CacheService;
import com.mszlu.shop.common.cache.CachePrefix;
import com.mszlu.shop.common.security.AuthUser;
import com.mszlu.shop.common.vo.Result;
import com.mszlu.shop.model.buyer.eums.trade.PayStatusEnum;
import com.mszlu.shop.model.buyer.exception.ServiceException;
import com.mszlu.shop.model.buyer.pojo.trade.Trade;
import com.mszlu.shop.model.buyer.vo.member.MemberAddressVo;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.util.Date;

@Service
@Slf4j
public class TradeServiceImpl implements TradeService {

    @Resource
    private TradeMapper tradeMapper;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private OrderService orderService;
    @Override
    @Transactional
    public Result<Trade> createTrade(TradeVo tradeVo, AuthUser authUser) {
        try {
            //创建订单预校验
            createTradeCheck(tradeVo);
            Trade trade = convertTrade(tradeVo);

            String key = CachePrefix.TRADE.name() + trade.getSn();
            //TODO 优惠券预处理
            //TODO 积分预处理
            //添加交易
            tradeMapper.insert(trade);
            //添加订单
            orderService.save(tradeVo,authUser);
            //写入缓存,给消费者调用
            cacheService.set(key, tradeVo,null);
            //构建订单创建消息
            String destination = "order:create";
            //发送订单创建消息
            rocketMQTemplate.asyncSend(destination, key, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    log.info("async onSuccess SendResult={}", sendResult);
                }

                @Override
                public void onException(Throwable throwable) {
                    log.error("async onException Throwable", throwable);
                }
            });
            return Result.success(trade);
        }catch (ServiceException e){
            e.printStackTrace();
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.fail(e.getResultCode(),e.getMessage());
        }
    }

    private Trade convertTrade(TradeVo tradeVo) {
        Trade trade = new Trade();
        if (tradeVo.getMemberAddress() != null) {
            BeanUtils.copyProperties(tradeVo.getMemberAddress(), trade);
            trade.setConsigneeMobile(tradeVo.getMemberAddress().getMobile());
            trade.setConsigneeName(tradeVo.getMemberAddress().getName());
        }
        BeanUtils.copyProperties(tradeVo, trade);
        BeanUtils.copyProperties(tradeVo.getPriceDetailDTO(), trade);
        trade.setPayStatus(PayStatusEnum.UNPAID.name());
        trade.setCreateTime(new Date());
        trade.setDeleteFlag(false);
        trade.setUpdateTime(new Date());
        return trade;
    }

    private void createTradeCheck(TradeVo tradeVo) {
        //创建订单如果没有收获地址,
        MemberAddressVo memberAddress = tradeVo.getMemberAddress();
        if (memberAddress == null) {
            throw new ServiceException(-999,"地址不存在");
        }
        //订单配送区域校验
        //TODO 正常有的商品有区域不配送,需要进行校验
    }
}

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
package com.mszlu.shop.buyer.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.shop.model.buyer.pojo.trade.Trade;

public interface TradeMapper extends BaseMapper<Trade> {
}

1
2
3
4
5
6
7
8

rocketmq相关:

 <dependency>
                <groupId>org.apache.rocketmq</groupId>
                <artifactId>rocketmq-spring-boot-starter</artifactId>
                <version>2.1.1</version>
            </dependency>
1
2
3
4
5
##rocketmq的配置
rocketmq.name-server=192.168.200.100:9876
rocketmq.producer.group=ms-mall
1
2
3

业务异常:

package com.mszlu.shop.model.buyer.exception;

import lombok.Data;

@Data
public class ServiceException extends RuntimeException {


    public static final String DEFAULT_MESSAGE = "网络错误,请稍后重试!";

    /**
     * 异常消息
     */
    private String msg = DEFAULT_MESSAGE;

    /**
     * 错误码
     */
    private int resultCode;

    public ServiceException(String msg) {
        this.resultCode = -999;
        this.msg = msg;
    }

    public ServiceException() {
        super();
    }

    public ServiceException(int resultCode) {
        this.resultCode = resultCode;
    }

    public ServiceException(int resultCode, String message) {
        this.resultCode = resultCode;
        this.msg = message;
    }

}
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

1.7 订单处理

1.7.1 数据库设计

1.7.1.1 订单 ms_order表:

image-20220106104915462

package com.mszlu.shop.model.buyer.pojo.order;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.mszlu.shop.model.buyer.dtos.trade.PriceDetailDTO;
import com.mszlu.shop.model.buyer.eums.CartTypeEnum;
import com.mszlu.shop.model.buyer.eums.goods.GoodsTypeEnum;
import com.mszlu.shop.model.buyer.eums.order.DeliverStatusEnum;
import com.mszlu.shop.model.buyer.eums.order.OrderStatusEnum;
import com.mszlu.shop.model.buyer.eums.order.OrderTypeEnum;
import com.mszlu.shop.model.buyer.eums.trade.PayStatusEnum;
import com.mszlu.shop.model.buyer.pojo.BaseEntity;
import com.mszlu.shop.model.buyer.vo.trade.CartVO;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * 订单
 */
@Data
@ApiModel(value = "订单")
@NoArgsConstructor
public class Order extends BaseEntity implements Serializable{
    @ApiModelProperty("唯一标识")
    private Long id;

    @ApiModelProperty("订单编号")
    private String sn;

    @ApiModelProperty("交易编号 关联Trade")
    private String tradeSn;

    @ApiModelProperty(value = "店铺ID")
    private String storeId;

    @ApiModelProperty(value = "店铺名称")
    private String storeName;

    @ApiModelProperty(value = "会员ID")
    private String memberId;

    @ApiModelProperty(value = "用户名")
    private String memberName;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.OrderStatusEnum
     */
    @ApiModelProperty(value = "订单状态")
    private String orderStatus;

    /**
     * @see com.mszlu.shop.model.buyer.eums.trade.PayStatusEnum
     */
    @ApiModelProperty(value = "付款状态")
    private String payStatus;
    /**
     * @see com.mszlu.shop.model.buyer.eums.order.DeliverStatusEnum
     */
    @ApiModelProperty(value = "货运状态")
    private String deliverStatus;

    @ApiModelProperty(value = "第三方付款流水号")
    private String receivableNo;

    @ApiModelProperty(value = "支付方式")
    private String paymentMethod;

    @ApiModelProperty(value = "支付时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date paymentTime;

    @ApiModelProperty(value = "收件人姓名")
    private String consigneeName;

    @ApiModelProperty(value = "收件人手机")
    private String consigneeMobile;

    /**
     * @see com.mszlu.shop.model.buyer.eums.trade.DeliveryMethodEnum
     */
    @ApiModelProperty(value = "配送方式")
    private String deliveryMethod;

    @ApiModelProperty(value = "地址名称, ','分割")
    private String consigneeAddressPath;

    @ApiModelProperty(value = "地址id,','分割 ")
    private String consigneeAddressIdPath;

    @ApiModelProperty(value = "详细地址")
    private String consigneeDetail;

    @ApiModelProperty(value = "总价格")
    private Double flowPrice;

    @ApiModelProperty(value = "商品价格")
    private Double goodsPrice;

    @ApiModelProperty(value = "运费")
    private Double freightPrice;

    @ApiModelProperty(value = "优惠的金额")
    private Double discountPrice;

    @ApiModelProperty(value = "修改价格")
    private Double updatePrice;

    @ApiModelProperty(value = "发货单号")
    private String logisticsNo;

    @ApiModelProperty(value = "物流公司CODE")
    private String logisticsCode;

    @ApiModelProperty(value = "物流公司名称")
    private String logisticsName;

    @ApiModelProperty(value = "订单商品总重量")
    private Double weight;

    @ApiModelProperty(value = "商品数量")
    private Integer goodsNum;

    @ApiModelProperty(value = "买家订单备注")
    private String remark;

    @ApiModelProperty(value = "订单取消原因")
    private String cancelReason;

    @ApiModelProperty(value = "完成时间")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date completeTime;

    @ApiModelProperty(value = "送货时间")
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    private Date logisticsTime;

    @ApiModelProperty(value = "支付方式返回的交易号")
    private String payOrderNo;

    /**
     * @see com.mszlu.shop.model.buyer.eums.ClientType
     */
    @ApiModelProperty(value = "订单来源")
    private String clientType;

    @ApiModelProperty(value = "是否需要发票")
    private Boolean needReceipt;

    @ApiModelProperty(value = "是否为其他订单下的订单,如果是则为依赖订单的sn,否则为空")
    private String parentOrderSn = "";

    @ApiModelProperty(value = "是否为某订单类型的订单,如果是则为订单类型的id,否则为空")
    private String promotionId;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.OrderTypeEnum
     */
    @ApiModelProperty(value = "订单类型")
    private String orderType;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.OrderPromotionTypeEnum
     */
    @ApiModelProperty(value = "订单促销类型")
    private String orderPromotionType;

    @ApiModelProperty(value = "价格详情")
    private String priceDetail;

    @ApiModelProperty(value = "订单是否支持原路退回")
    private Boolean canReturn;

    @ApiModelProperty(value = "提货码")
    private String verificationCode;

    @ApiModelProperty(value = "分销员ID")
    private String distributionId;

    @ApiModelProperty(value = "使用的店铺会员优惠券id(,区分)")
    private String useStoreMemberCouponIds;

    @ApiModelProperty(value = "使用的平台会员优惠券id")
    private String usePlatformMemberCouponId;

    /**
     * 构建订单
     *
     * @param cartVO   购物车VO
     * @param tradeVo 交易VO
     */
    public Order(CartVO cartVO, TradeVo tradeVo) {
        BeanUtils.copyProperties(tradeVo, this);
        BeanUtils.copyProperties(cartVO.getPriceDetailDTO(), this);
        BeanUtils.copyProperties(cartVO, this);
        //填写订单类型
        this.setTradeType(cartVO, tradeVo);

        //设置默认支付状态
        this.setOrderStatus(OrderStatusEnum.UNPAID.name());
        this.setPayStatus(PayStatusEnum.UNPAID.name());
        this.setDeliverStatus(DeliverStatusEnum.UNDELIVERED.name());
        this.setTradeSn(tradeVo.getSn());
        this.setRemark(cartVO.getRemark());
        this.setFreightPrice(tradeVo.getPriceDetailDTO().getFreightPrice());
        //会员收件信息
        this.setConsigneeAddressIdPath(tradeVo.getMemberAddress().getConsigneeAddressIdPath());
        this.setConsigneeAddressPath(tradeVo.getMemberAddress().getConsigneeAddressPath());
        this.setConsigneeDetail(tradeVo.getMemberAddress().getDetail());
        this.setConsigneeMobile(tradeVo.getMemberAddress().getMobile());
        this.setConsigneeName(tradeVo.getMemberAddress().getName());
        //平台优惠券判定
//        if (tradeVo.getPlatformCoupon() != null) {
//            this.setUsePlatformMemberCouponId(tradeVo.getPlatformCoupon().getMemberCoupon().getId());
//        }
        //店铺优惠券判定
//        if (tradeVo.getStoreCoupons() != null && !tradeVo.getStoreCoupons().isEmpty()) {
//            StringBuilder storeCouponIds = new StringBuilder();
//            for (String s : tradeVo.getStoreCoupons().keySet()) {
//                storeCouponIds.append(s).append(",");
//            }
//            this.setUseStoreMemberCouponIds(storeCouponIds.toString());
//        }

    }


    /**
     * 填写交易(订单)类型
     * 1.判断是普通、促销订单
     * 2.普通订单进行区分:实物订单、虚拟订单
     * 3.促销订单判断货物进行区分实物、虚拟商品。
     * 4.拼团订单需要填写父订单ID
     *
     * @param cartVO   购物车VO
     * @param tradeVo 交易VO
     */
    private void setTradeType(CartVO cartVO, TradeVo tradeVo) {

        //判断是否为普通订单、促销订单
        if (tradeVo.getCartTypeEnum().equals(CartTypeEnum.CART) || tradeVo.getCartTypeEnum().equals(CartTypeEnum.BUY_NOW)) {
            this.setOrderType(OrderTypeEnum.NORMAL.name());
        } else if (tradeVo.getCartTypeEnum().equals(CartTypeEnum.VIRTUAL)) {
            this.setOrderType(OrderTypeEnum.VIRTUAL.name());
        } else {
            //促销订单(拼团、积分)-判断购买的是虚拟商品还是实物商品
            Integer goodsType = cartVO.checkedSkuList().get(0).getGoodsSku().getGoodsType();
            if (goodsType == null || goodsType.equals(GoodsTypeEnum.PHYSICAL_GOODS.getCode())) {
                this.setOrderType(OrderTypeEnum.NORMAL.name());
            } else {
                this.setOrderType(OrderTypeEnum.VIRTUAL.name());
            }
            //填写订单的促销类型
            this.setOrderPromotionType(tradeVo.getCartTypeEnum().name());

            //判断是否为拼团订单,如果为拼团订单获取拼团ID,判断是否为主订单
//            if (tradeVo.getCartTypeEnum().name().equals(PromotionTypeEnum.PINTUAN.name())) {
//                Optional<String> pintuanId = cartVO.getCheckedSkuList().get(0).getPromotions().stream()
//                        .filter(i -> i.getPromotionType().equals(PromotionTypeEnum.PINTUAN.name())).map(PromotionGoods::getPromotionId).findFirst();
//                promotionId = pintuanId.get();
//            }
        }
    }


    public PriceDetailDTO getPriceDetailDTO() {
        try {
            return JSON.parseObject(priceDetail, PriceDetailDTO.class);
        } catch (Exception e) {
            return null;
        }
    }

    public void setPriceDetailDTO(PriceDetailDTO priceDetail) {
        this.priceDetail = JSON.toJSONString(priceDetail);
    }


}
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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 订单类型枚举
 */
public enum OrderTypeEnum {

    /**
     * 普通订单
     */
    NORMAL,

    /**
     * 虚拟订单
     */
    VIRTUAL
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 订单状态枚举
 */
public enum OrderStatusEnum {

    /**
     * 订单状态
     */
    UNPAID("未付款"),
    PAID("已付款"),
    UNDELIVERED("待发货"),
    DELIVERED("已发货"),
    COMPLETED("已完成"),
    /**
     * 虚拟订单需要核验商品
     */
    TAKE("待核验"),
    CANCELLED("已取消");

    private final String description;

    OrderStatusEnum(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public String description() {
        return this.description;
    }


}

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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 订单促销类型枚举
 */
public enum OrderPromotionTypeEnum {

    /**
     * 普通订单
     */
    NORMAL,
    /**
     * 赠品订单
     */
    GIFT,
    /**
     * 拼团订单
     */
    PINTUAN,
    /**
     * 积分订单
     */
    POINTS,
    /**
     * 砍价订单
     */
    KANJIA

}

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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 发货状态枚举
 */
public enum DeliverStatusEnum {

    /**
     * 发货状态
     */
    UNDELIVERED("未发货"),
    DELIVERED("已发货"),
    RECEIVED("已收货");


    private final String description;

    DeliverStatusEnum(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

}

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

CartVo:

/**
     * 过滤购物车中已选择的sku
     *
     * @return
     */
    public List<CartSkuVO> checkedSkuList() {
        if (skuList != null && !skuList.isEmpty()) {
            return skuList.stream().filter(CartSkuVO::getChecked).collect(Collectors.toList());
        }
        return skuList;
    }
1
2
3
4
5
6
7
8
9
10
11
1.7.1.2 子订单:ms_order_item

image-20220106115504016

package com.mszlu.shop.model.buyer.pojo.order;

import com.alibaba.fastjson.JSON;
import com.mszlu.shop.common.utils.SnowFlake;
import com.mszlu.shop.model.buyer.dtos.trade.PriceDetailDTO;
import com.mszlu.shop.model.buyer.eums.order.CommentStatusEnum;
import com.mszlu.shop.model.buyer.eums.order.OrderComplaintStatusEnum;
import com.mszlu.shop.model.buyer.eums.order.OrderItemAfterSaleStatusEnum;
import com.mszlu.shop.model.buyer.pojo.BaseEntity;
import com.mszlu.shop.model.buyer.vo.trade.CartSkuVO;
import com.mszlu.shop.model.buyer.vo.trade.CartVO;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;

import java.math.BigDecimal;
import java.util.stream.Collectors;

/**
 * 子订单
 */
@Data
@ApiModel(value = "子订单")
@NoArgsConstructor
@AllArgsConstructor
public class OrderItem extends BaseEntity implements Serializable{


    private Long id;
    @ApiModelProperty(value = "订单编号")
    private String orderSn;

    @ApiModelProperty(value = "子订单编号")
    private String sn;

    @ApiModelProperty(value = "单价")
    private Double unitPrice;

    @ApiModelProperty(value = "小记")
    private Double subTotal;

    @ApiModelProperty(value = "商品ID")
    private String goodsId;

    @ApiModelProperty(value = "货品ID")
    private String skuId;

    @ApiModelProperty(value = "销售量")
    private Integer num;

    @ApiModelProperty(value = "交易编号")
    private String tradeSn;

    @ApiModelProperty(value = "图片")
    private String image;

    @ApiModelProperty(value = "商品名称")
    private String goodsName;

    @ApiModelProperty(value = "分类ID")
    private String categoryId;

    @ApiModelProperty(value = "快照id")
    private String snapshotId;

    @ApiModelProperty(value = "规格json")
    private String specs;

    @ApiModelProperty(value = "促销类型")
    private String promotionType;

    @ApiModelProperty(value = "促销id")
    private String promotionId;

    @ApiModelProperty(value = "销售金额")
    private BigDecimal goodsPrice;

    @ApiModelProperty(value = "实际金额")
    private Double flowPrice;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.CommentStatusEnum
     */
    @ApiModelProperty(value = "评论状态:未评论(UNFINISHED),待追评(WAIT_CHASE),评论完成(FINISHED),")
    private String commentStatus;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.OrderItemAfterSaleStatusEnum
     */
    @ApiModelProperty(value = "售后状态")
    private String afterSaleStatus;

    @ApiModelProperty(value = "价格详情")
    private String priceDetail;

    /**
     * @see com.mszlu.shop.model.buyer.eums.order.OrderComplaintStatusEnum
     */
    @ApiModelProperty(value = "投诉状态")
    private String complainStatus;

    @ApiModelProperty(value = "交易投诉id")
    private String complainId;

    @ApiModelProperty(value = "退货商品数量")
    private Integer returnGoodsNumber;


    public OrderItem(CartSkuVO cartSkuVO, CartVO cartVO, TradeVo tradeVo) {
        BeanUtils.copyProperties(cartSkuVO.getGoodsSku(), this);
        this.goodsId = cartSkuVO.getGoodsSku().getGoodsId().toString();
        BeanUtils.copyProperties(cartSkuVO.getPriceDetailDTO(), this);
        BeanUtils.copyProperties(cartSkuVO, this);

        this.setAfterSaleStatus(OrderItemAfterSaleStatusEnum.NEW.name());
        this.setCommentStatus(CommentStatusEnum.NEW.name());
        this.setComplainStatus(OrderComplaintStatusEnum.NEW.name());
        this.setPriceDetailDTO(cartSkuVO.getPriceDetailDTO());
        this.setOrderSn(cartVO.getSn());
        this.setTradeSn(tradeVo.getSn());
        this.setImage(cartSkuVO.getGoodsSku().getThumbnail());
        this.setGoodsName(cartSkuVO.getGoodsSku().getGoodsName());
        this.setSkuId(cartSkuVO.getGoodsSku().getId().toString());
        this.setCategoryId(cartSkuVO.getGoodsSku().getCategoryPath().substring(
                cartSkuVO.getGoodsSku().getCategoryPath().lastIndexOf(",") + 1
        ));
        this.setGoodsPrice(cartSkuVO.getGoodsSku().getPrice());
        this.setUnitPrice(cartSkuVO.getPurchasePrice());
        this.setSubTotal(cartSkuVO.getSubTotal());
        this.setSn(SnowFlake.createStr("OI"));


    }

    public PriceDetailDTO getPriceDetailDTO() {
        return JSON.parseObject(priceDetail, PriceDetailDTO.class);
    }

    public void setPriceDetailDTO(PriceDetailDTO priceDetail) {
        this.priceDetail = JSON.toJSONString(priceDetail);
    }

}
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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 订单的投诉状态
 **/
public enum OrderComplaintStatusEnum {

    /**
     * 新订单,不能申请投诉
     */
    NEW("待审核"),
    /**
     * 未申请
     */
    NO_APPLY("未申请"),
    /**
     * 申请中
     */
    APPLYING("申请中"),
    /**
     * 已完成
     */
    COMPLETE("已完成"),
    /**
     * 已失效
     */
    EXPIRED("已失效"),
    /**
     * 取消
     */
    CANCEL("取消");

    private final String description;

    OrderComplaintStatusEnum(String description) {
        this.description = description;
    }

    public String description() {
        return this.description;
    }


}

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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 评论状态枚举
 */
public enum CommentStatusEnum {

    /**
     * 新订单,不能进行评论
     */
    NEW("新订单,不能进行评论"),
    /**
     * 未完成的评论
     */
    UNFINISHED("未完成评论"),

    /**
     * 待追评的评论信息
     */
    WAIT_CHASE("待追评评论"),

    /**
     * 已经完成评论
     */
    FINISHED("已经完成评论");

    private final String description;

    CommentStatusEnum(String description) {
        this.description = description;
    }

    public String description() {
        return this.description;
    }

}

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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * 订单可申请售后状态枚举
 */
public enum OrderItemAfterSaleStatusEnum {

    /**
     * 订单申请售后状态
     */
    NEW("新订单,不能申请售后"),
    NOT_APPLIED("未申请"),
    ALREADY_APPLIED("已申请"),
    EXPIRED("已失效不允许申请售后"),
    PART_AFTER_SALE("部分售后");



    private final String description;

    OrderItemAfterSaleStatusEnum(String description) {
        this.description = description;
    }

    public String description() {
        return this.description;
    }

}

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

分布式id获取

package com.mszlu.shop.common.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;

/**
 * 雪花分布式id获取
 */
public class SnowFlake {

    /**
     * 机器id
     */
    private static long workerId = 0L;
    /**
     * 机房id
     */
    private static long datacenterId = 0L;

    private static Snowflake snowflake = IdUtil.createSnowflake(workerId, datacenterId);

    public static long getId() {
        return snowflake.nextId();
    }

    /**
     * 生成字符,带有前缀
     * @param prefix
     * @return
     */
    public static String createStr(String prefix) {
        return prefix + new DateTime().toString("yyyyMMdd") + SnowFlake.getId();
    }
    public static String getIdStr() {
        return snowflake.nextId() + "";
    }
}

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
1.7.1.3 订单日志

image-20220106120404275

package com.mszlu.shop.model.buyer.pojo.order;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.mszlu.shop.model.buyer.pojo.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.util.Date;

/**
 * 订单日志
 */
@Data
@ApiModel(value = "订单日志")
@NoArgsConstructor
public class OrderLog implements Serializable {

    private Long id;

    @CreatedDate
    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "创建时间", hidden = true)
    private Date createTime;

    @ApiModelProperty(value = "订单编号")
    private String orderSn;

    @ApiModelProperty(value = "操作者id(可以是卖家)")
    private String operatorId;
    /**
     * @see com.mszlu.shop.model.buyer.eums.order.UserEnums
     */
    @ApiModelProperty(value = "操作者类型")
    private String operatorType;


    @ApiModelProperty(value = "操作者名称")
    private String operatorName;

    @ApiModelProperty(value = "日志信息")
    private String message;

    public OrderLog(String orderSn, String operatorId, String operatorType, String operatorName, String message) {
        this.orderSn = orderSn;
        this.operatorId = operatorId;
        this.operatorType = operatorType;
        this.operatorName = operatorName;
        this.message = message;
        this.createTime = new Date();
    }

}
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
package com.mszlu.shop.model.buyer.eums.order;

/**
 * token角色类型
 */
public enum UserEnums {
    /**
     * 角色
     */
    MEMBER("会员"),
    STORE("商家"),
    MANAGER("管理员"),
    SYSTEM("系统");
    private final String role;

    UserEnums(String role) {
        this.role = role;
    }

    public String getRole() {
        return role;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

1.7.2 编码

订单vo

package com.mszlu.shop.model.buyer.vo.order;

import com.mszlu.shop.model.buyer.pojo.order.Order;
import com.mszlu.shop.model.buyer.pojo.order.OrderItem;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;

import java.io.Serializable;
import java.util.List;

/**
 * 订单vo
 */
@Data
@NoArgsConstructor
public class OrderVO extends Order implements Serializable {


    @ApiModelProperty(value = "订单商品项目")
    private List<OrderItem> orderItems;


    public OrderVO (Order order,List<OrderItem> orderItems){
        BeanUtils.copyProperties(order, this);
        this.setOrderItems(orderItems);
    }
}

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
1.7.2.1 OrderService
package com.mszlu.shop.buyer.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.mszlu.shop.common.security.AuthUser;
import com.mszlu.shop.model.buyer.pojo.order.Order;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;

public interface OrderService extends IService<Order> {

    void save(TradeVo tradeVo, AuthUser authUser);
}

1
2
3
4
5
6
7
8
9
10
11
12
1.7.2.2 Impl
package com.mszlu.shop.buyer.service.impl.order;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mszlu.shop.buyer.mapper.OrderMapper;
import com.mszlu.shop.buyer.service.OrderItemService;
import com.mszlu.shop.buyer.service.OrderLogService;
import com.mszlu.shop.buyer.service.impl.CacheService;
import com.mszlu.shop.common.security.AuthUser;
import com.mszlu.shop.model.buyer.pojo.order.Order;
import com.mszlu.shop.model.buyer.pojo.order.OrderItem;
import com.mszlu.shop.model.buyer.pojo.order.OrderLog;
import com.mszlu.shop.model.buyer.vo.order.OrderVO;
import com.mszlu.shop.model.buyer.vo.trade.TradeVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper,Order> implements OrderService {

    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderLogService orderLogService;
    @Autowired
    private CacheService cacheService;

    @Override
    public void save(TradeVo tradeVo, AuthUser authUser) {
        //1. 如果是拼团用户是不能参加自己的拼团,这里暂时不涉及
        //存放购物车,即业务中的订单
        List<Order> orders = new ArrayList<>(tradeVo.getCartList().size());
        //存放子订单/订单日志
        List<OrderItem> orderItems = new ArrayList<>();
        List<OrderLog> orderLogs = new ArrayList<>();
        //订单集合
        List<OrderVO> orderVOS = new ArrayList<>();
        //循环购物车
        tradeVo.getCartList().forEach(item -> {
            Order order = new Order(item, tradeVo);
            //构建orderVO对象
            OrderVO orderVO = new OrderVO();
            BeanUtils.copyProperties(order, orderVO);
            //持久化
            orders.add(order);
            String message = "订单[" + item.getSn() + "]创建";
            //记录日志
            orderLogs.add(new OrderLog(item.getSn(), authUser.getId(), authUser.getRole().getRole(), authUser.getUsername(), message));
            item.checkedSkuList().forEach(
                    sku -> orderItems.add(new OrderItem(sku, item, tradeVo))
            );
            //写入子订单信息
            orderVO.setOrderItems(orderItems);
            //orderVO 记录
            orderVOS.add(orderVO);
        });
        tradeVo.setOrderVO(orderVOS);
        //批量保存订单
        this.saveBatch(orders);
        //批量保存 子订单
        orderItemService.saveBatch(orderItems);
        //批量记录订单操作日志
        orderLogService.saveBatch(orderLogs);
      
    }
}

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
package com.mszlu.shop.buyer.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.mszlu.shop.model.buyer.pojo.order.OrderItem;

public interface OrderItemService extends IService<OrderItem> {
}

1
2
3
4
5
6
7
8
package com.mszlu.shop.buyer.service.impl.order;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mszlu.shop.buyer.mapper.OrderLogMapper;
import com.mszlu.shop.buyer.service.OrderLogService;
import com.mszlu.shop.model.buyer.pojo.order.OrderLog;
import org.springframework.stereotype.Service;

@Service
public class OrderLogServiceImpl extends ServiceImpl<OrderLogMapper, OrderLog> implements OrderLogService {
}

1
2
3
4
5
6
7
8
9
10
11
12
package com.mszlu.shop.buyer.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.shop.model.buyer.pojo.order.OrderItem;
import com.mszlu.shop.model.buyer.pojo.order.OrderLog;

public interface OrderLogMapper extends BaseMapper<OrderLog> {
}

1
2
3
4
5
6
7
8
9
package com.mszlu.shop.buyer.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.shop.model.buyer.pojo.order.OrderItem;

public interface OrderItemMapper extends BaseMapper<OrderItem> {
}

1
2
3
4
5
6
7
8
package com.mszlu.shop.buyer.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mszlu.shop.model.buyer.pojo.order.Order;

public interface OrderMapper extends BaseMapper<Order> {
}

1
2
3
4
5
6
7
8

1.8 测试

2. 获取支付详情

2.1 接口说明

请求url:/buyer/cashier/tradeDetail?orderType=TRADE&sn=T202202111492156987054489600&clientType=0

参数:?号传参,orderType是订单类型,sn是订单号