首页 > 其他分享 >HM-RocketMQ2.5【下单业务】

HM-RocketMQ2.5【下单业务】

时间:2022-12-08 12:12:28浏览次数:42  
标签:SHOP RocketMQ2.5 BigDecimal ShopCode 订单 CastException 下单 HM order

1 下单业务时序图

image-20221124141903033

调用下单服务:远程RPC调用订单服务

预订单:用户不可见

扣减库存:远程RPC调用库存服务

扣减优惠券:远程RPC调用优惠券服务

扣减用户预测:远程RPC调用用户服务

确认订单:将预订单状态改为用户可见

确认订单成功-->生成订单成功-->返回下单结果

确认订单成功-->MQ监听-->回退以上扣减&取消订单

2 下单基本流程(下单成功)

2.1 接口定义

shop-api模块

package com.irun2u.api;

import com.irun2u.entity.Result;
import com.irun2u.shop.pojo.TradeOrder;

/**
 * @Author: haifei
 * @Date: 2022/12/5 15:20
 */
public interface OrderService {

    /**
     * 确认订单
     * @param order
     * @return
     */
    Result confirmOrder(TradeOrder order);
}

2.2 业务类实现

shop-order-service模块

package com.irun2u.service.impl;

import com.irun2u.api.OrderService;
import com.irun2u.entity.Result;
import com.irun2u.shop.pojo.TradeOrder;

/**
 * @Author: haifei
 * @Date: 2022/12/5 15:23
 */
public class OrderServiceImpl implements OrderService {

    @Override
    public Result confirmOrder(TradeOrder order) {
        //1.校验订单
        //2.生成预订单
        try {
            // 保证3-7的原子性
            //3.扣减库存
            //4.扣减优惠券
            //5.使用余额
            //6.确认订单
            //7.返回成功状态
        } catch (Exception e) {
            //1.确认订单失败,发送消息
            //2.返回失败状态
            //以上具体实现详见2.9
        }
        return null;
    }

}

2.3 校验订单

校验订单(2)

/**
     * 校验订单
     * @param order
     */
private void checkOrder(TradeOrder order) {
    //1.校验订单是否存在
    if (order == null){
        CastException.cast(ShopCode.SHOP_ORDER_INVALID);
    }
    //2.校验订单中的商品是否存在
    TradeGoods goods = goodsService.findOne(order.getGoodsId());
    if (goods == null){
        CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
    }
    //3.校验下单用户是否存在
    TradeUser user = userService.findOne(order.getUserId());
    if (user == null){
        CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
    }
    //4.校验订单金额是否合法
    //        if (order.getPayAmount().compareTo(goods.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()))) != 0){
    if (order.getGoodsPrice().compareTo(goods.getGoodsPrice()) != 0){
        CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
    }
    //5.校验订单商品数量是否合法
    if (order.getGoodsNumber() >= goods.getGoodsNumber()){
        CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
    }
    log.info("校验订单通过");
}

2.4 生成预订单

生成预订单

/**
     * 生成预订单
     * @param order
     * @return
     */
    private Long savePreOrder(TradeOrder order){
        //1.设置订单状态不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        //2.设置订单id
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        //3.核算订单运费是否合法
        BigDecimal shippingFee = calculateShippinFee(order.getOrderAmount());
        if (order.getShippingFee().compareTo(shippingFee) != 0){
            CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);
        }
        //4.核算订单总金额是否合法
        BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        orderAmount.add(shippingFee);
        if (order.getOrderAmount().compareTo(orderAmount) != 0){
            CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        }
        //5.判断用户是否使用余额
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (moneyPaid != null){
            //5.1判断订单中余额是否合法
            int r = moneyPaid.compareTo(BigDecimal.ZERO);
            if (r == -1){ //余额小于0
                CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);
            }
            if (r == 1){ //余额大于0
                TradeUser user = userService.findOne(order.getUserId());
                if (moneyPaid.compareTo(new BigDecimal(user.getUserMoney())) == 1){ //订单所需money大于用户所拥有余额
                    CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);
                }
            }
        }else {
            order.setMoneyPaid(BigDecimal.ZERO);
        }
        //6.判断用户是否使用优惠券
        Long couponId = order.getCouponId();
        if (couponId != null){
            TradeCoupon coupon = couponService.findOne(couponId);
            //6.1判断优惠券是否存在
            if (coupon == null){
                CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);
            }
            //6.2判断优惠券是否已被使用
            if (coupon.getIsUsed().intValue() == ShopCode.SHOP_COUPON_ISUSED.getCode()){
                CastException.cast(ShopCode.SHOP_COUPON_ISUSED);
            }
        }else {
            order.setCouponPaid(BigDecimal.ZERO);
        }
        //7.核算订单支付金额[=订单总金额-余额-优惠券金额]
        BigDecimal payAmount = order.getOrderAmount().subtract(order.getMoneyPaid()).subtract(order.getCouponPaid());
        order.setPayAmount(payAmount);
        //8.设置下单时间
        order.setAddTime(new Date());
        //9.保存订单到数据库
        orderMapper.insert(order);
        //10.返回订单id
        return orderId;
    }

2.5 扣减库存

通过dubbo调用商品服务完成扣减库存

/**
     * 扣减库存
     * @param order
     */
    private void reduceGoodsNum(TradeOrder order) {
        TradeGoodsNumberLog goodsNumberLog = new TradeGoodsNumberLog();
        goodsNumberLog.setOrderId(order.getOrderId());
        goodsNumberLog.setGoodsId(order.getGoodsId());
        goodsNumberLog.setGoodsNumber(order.getGoodsNumber());
        Result result = goodsService.reduceGoodsNum(goodsNumberLog);
        if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getCode())){
            CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        }
        log.info("订单:" + order.getOrderId() + "扣减库存成功");
    }
/**
     * 扣减库存
     * @param goodsNumberLog
     * @return
     */
    Result reduceGoodsNum(TradeGoodsNumberLog goodsNumberLog);

商品服务GoodsService扣减库存

@Override
    public Result reduceGoodsNum(TradeGoodsNumberLog goodsNumberLog) {
        if (goodsNumberLog == null ||
            goodsNumberLog.getGoodsNumber() == null ||
            goodsNumberLog.getGoodsId() == null ||
            goodsNumberLog.getOrderId() == null ||
            goodsNumberLog.getGoodsNumber() <= 0){
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }
        TradeGoods goods = goodsMapper.selectByPrimaryKey(goodsNumberLog.getGoodsId());
        if (goods.getGoodsNumber() < goodsNumberLog.getGoodsNumber()){
            //库存不足
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        //减库存、更新库存
        goods.setGoodsNumber(goods.getGoodsNumber() - goodsNumberLog.getGoodsNumber());
        goodsMapper.updateByPrimaryKey(goods);
        //记录库存操作的日志
        goodsNumberLog.setGoodsNumber( -(goodsNumberLog.getGoodsNumber()) );
        goodsNumberLog.setLogTime(new Date());
        goodsNumberLogMapper.insert(goodsNumberLog);
        return new Result(ShopCode.SHOP_SUCCESS.getSuccess(), ShopCode.SHOP_SUCCESS.getMessage());
    }

2.6 扣减优惠券

通过dubbo完成扣减优惠券

/**
     * 扣减优惠券
     * @param order
     */
    private void updateCouponStatus(TradeOrder order) {
        if(order.getCouponId()!=null){
            TradeCoupon coupon = couponService.findOne(order.getCouponId());
            coupon.setOrderId(order.getOrderId());
            coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
            coupon.setUsedTime(new Date());
            //更新优惠券状态
            Result result =  couponService.updateCouponStatus(coupon);
            if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){
                CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);
            }
            log.info("订单:"+order.getOrderId()+",使用优惠券");
        }
    }
/**
     * 更新优惠券状态
     * @param coupon
     * @return
     */
    Result updateCouponStatus(TradeCoupon coupon);

优惠券服务CouponService更改优惠券状态

@Override
    public Result updateCouponStatus(TradeCoupon coupon) {
        if(coupon==null||coupon.getCouponId()==null){
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }
        //更新优惠券状态
        couponMapper.updateByPrimaryKey(coupon);
        return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());
    }

2.7 扣减用户余额

/**
     * 扣减余额
     * @param order
     */
    private void reduceMoneyPaid(TradeOrder order) {
        if(order.getMoneyPaid()!=null && order.getMoneyPaid().compareTo(BigDecimal.ZERO)==1){
            TradeUserMoneyLog userMoneyLog = new TradeUserMoneyLog();
            userMoneyLog.setOrderId(order.getOrderId());
            userMoneyLog.setUserId(order.getUserId());
            userMoneyLog.setUseMoney(order.getMoneyPaid());
            userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());
            Result result = userService.updateMoneyPaid(userMoneyLog);
            if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){
                CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            }
            log.info("订单:"+order.getOrderId()+",扣减余额成功");
        }
    }
/**
     * 更新用户余额
     * @param userMoneyLog
     * @return
     */
    Result updateMoneyPaid(TradeUserMoneyLog userMoneyLog);

image-20221208102508493

@Override
    public Result updateMoneyPaid(TradeUserMoneyLog userMoneyLog) {
        //1.校验参数是否合法
        if(userMoneyLog==null ||
                userMoneyLog.getUserId()==null ||
                userMoneyLog.getOrderId()==null ||
                userMoneyLog.getUseMoney()==null||
                userMoneyLog.getUseMoney().compareTo(BigDecimal.ZERO)<=0){
            CastException.cast(ShopCode.SHOP_REQUEST_PARAMETER_VALID);
        }

        //2.查询订单余额使用日志
        TradeUserMoneyLogExample userMoneyLogExample = new TradeUserMoneyLogExample();
        TradeUserMoneyLogExample.Criteria criteria = userMoneyLogExample.createCriteria();
        criteria.andOrderIdEqualTo(userMoneyLog.getOrderId());
        criteria.andUserIdEqualTo(userMoneyLog.getUserId());
        int r = userMoneyLogMapper.countByExample(userMoneyLogExample);

        TradeUser tradeUser = userMapper.selectByPrimaryKey(userMoneyLog.getUserId());

        //3.扣减余额...
        if(userMoneyLog.getMoneyLogType().intValue()==ShopCode.SHOP_USER_MONEY_PAID.getCode().intValue()){
            if(r>0){
                //已经付款
                CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_IS_PAY);
            }
            //减余额
            tradeUser.setUserMoney(new BigDecimal(tradeUser.getUserMoney()).subtract(userMoneyLog.getUseMoney()).longValue());
            userMapper.updateByPrimaryKey(tradeUser);
        }

        //4.回退余额...
        if(userMoneyLog.getMoneyLogType().intValue()==ShopCode.SHOP_USER_MONEY_REFUND.getCode().intValue()){
            if(r==0){ //count查询不可能为复数,所以不会<0,没查到就是0
                //如果没有支付,则不能回退余额
                CastException.cast(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY);
            }
            //防止多次退款
            TradeUserMoneyLogExample userMoneyLogExample2 = new TradeUserMoneyLogExample();
            TradeUserMoneyLogExample.Criteria criteria1 = userMoneyLogExample2.createCriteria();
            criteria1.andOrderIdEqualTo(userMoneyLog.getOrderId());
            criteria1.andUserIdEqualTo(userMoneyLog.getUserId());
            criteria1.andMoneyLogTypeEqualTo(ShopCode.SHOP_USER_MONEY_REFUND.getCode());
            int r2 = userMoneyLogMapper.countByExample(userMoneyLogExample2);
            if(r2>0){
                CastException.cast(ShopCode.SHOP_USER_MONEY_REFUND_ALREADY);
            }
            //退款
            tradeUser.setUserMoney(new BigDecimal(tradeUser.getUserMoney()).add(userMoneyLog.getUseMoney()).longValue());
            userMapper.updateByPrimaryKey(tradeUser);
        }

        //5.记录订单余额使用日志
        userMoneyLog.setCreateTime(new Date());
        userMoneyLogMapper.insert(userMoneyLog);
        return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());
    }

2.8 确认订单

/**
     * 确认订单(修改预订单状态)
     * @param order
     */
    private void updateOrderStatus(TradeOrder order) {
        order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());
        order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());
        order.setConfirmTime(new Date());
        int r = orderMapper.updateByPrimaryKey(order);
        if(r<=0){
            CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        }
        log.info("订单:"+order.getOrderId()+"确认订单成功");
    }

2.9 小结(完整源码)

package com.irun2u.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.irun2u.api.CouponService;
import com.irun2u.api.GoodsService;
import com.irun2u.api.OrderService;
import com.irun2u.api.UserService;
import com.irun2u.constant.ShopCode;
import com.irun2u.entity.Result;
import com.irun2u.exception.CastException;
import com.irun2u.mapper.TradeOrderMapper;
import com.irun2u.shop.pojo.*;
import com.irun2u.utils.IDWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @Author: haifei
 * @Date: 2022/12/5 15:23
 */
@Slf4j
@Component
@Service(interfaceClass = OrderService.class)
public class OrderServiceImpl implements OrderService {

    @Reference
    private GoodsService goodsService;

    @Reference
    private UserService userService;

    @Reference
    private CouponService couponService;

    @Autowired
    private IDWorker idWorker;

    @Autowired
    private TradeOrderMapper orderMapper;

    @Override
    public Result confirmOrder(TradeOrder order) {
        //1.校验订单
        checkOrder(order);
        //2.生成预订单
        Long orderId = savePreOrder(order);
        try {// 保证3-7的原子性
            //3.扣减库存
            reduceGoodsNum(order);
            //4.扣减优惠券
            updateCouponStatus(order);
            //5.扣减余额
            reduceMoneyPaid(order);
            //6.确认订单
            updateOrderStatus(order);
            //7.返回成功状态
            return new Result(ShopCode.SHOP_SUCCESS.getSuccess(),ShopCode.SHOP_SUCCESS.getMessage());
        } catch (Exception e) {
            //1.确认订单失败,发送消息

            //2.返回失败状态
            return new Result(ShopCode.SHOP_FAIL.getSuccess(),ShopCode.SHOP_FAIL.getMessage());
        }
    }

    /**
     * 确认订单(修改预订单状态)
     * @param order
     */
    private void updateOrderStatus(TradeOrder order) {
        order.setOrderStatus(ShopCode.SHOP_ORDER_CONFIRM.getCode());
        order.setPayStatus(ShopCode.SHOP_ORDER_PAY_STATUS_NO_PAY.getCode());
        order.setConfirmTime(new Date());
        int r = orderMapper.updateByPrimaryKey(order);
        if(r<=0){
            CastException.cast(ShopCode.SHOP_ORDER_CONFIRM_FAIL);
        }
        log.info("订单:"+order.getOrderId()+"确认订单成功");
    }

    /**
     * 扣减余额
     * @param order
     */
    private void reduceMoneyPaid(TradeOrder order) {
        if(order.getMoneyPaid()!=null && order.getMoneyPaid().compareTo(BigDecimal.ZERO)==1){
            TradeUserMoneyLog userMoneyLog = new TradeUserMoneyLog();
            userMoneyLog.setOrderId(order.getOrderId());
            userMoneyLog.setUserId(order.getUserId());
            userMoneyLog.setUseMoney(order.getMoneyPaid());
            userMoneyLog.setMoneyLogType(ShopCode.SHOP_USER_MONEY_PAID.getCode());
            Result result = userService.updateMoneyPaid(userMoneyLog);
            if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){
                CastException.cast(ShopCode.SHOP_USER_MONEY_REDUCE_FAIL);
            }
            log.info("订单:"+order.getOrderId()+",扣减余额成功");
        }
    }

    /**
     * 扣减优惠券
     * @param order
     */
    private void updateCouponStatus(TradeOrder order) {
        if(order.getCouponId()!=null){
            TradeCoupon coupon = couponService.findOne(order.getCouponId());
            coupon.setOrderId(order.getOrderId());
            coupon.setIsUsed(ShopCode.SHOP_COUPON_ISUSED.getCode());
            coupon.setUsedTime(new Date());
            //更新优惠券状态
            Result result =  couponService.updateCouponStatus(coupon);
            if(result.getSuccess().equals(ShopCode.SHOP_FAIL.getSuccess())){
                CastException.cast(ShopCode.SHOP_COUPON_USE_FAIL);
            }
            log.info("订单:"+order.getOrderId()+",使用优惠券");
        }
    }

    /**
     * 扣减库存
     * @param order
     */
    private void reduceGoodsNum(TradeOrder order) {
        TradeGoodsNumberLog goodsNumberLog = new TradeGoodsNumberLog();
        goodsNumberLog.setOrderId(order.getOrderId());
        goodsNumberLog.setGoodsId(order.getGoodsId());
        goodsNumberLog.setGoodsNumber(order.getGoodsNumber());
        Result result = goodsService.reduceGoodsNum(goodsNumberLog);
        if (result.getSuccess().equals(ShopCode.SHOP_FAIL.getCode())){
            CastException.cast(ShopCode.SHOP_REDUCE_GOODS_NUM_FAIL);
        }
        log.info("订单:" + order.getOrderId() + "扣减库存成功");
    }


    /**
     * 校验订单
     * @param order
     */
    private void checkOrder(TradeOrder order) {
        //1.校验订单是否存在
        if (order == null){
            CastException.cast(ShopCode.SHOP_ORDER_INVALID);
        }
        //2.校验订单中的商品是否存在
        TradeGoods goods = goodsService.findOne(order.getGoodsId());
        if (goods == null){
            CastException.cast(ShopCode.SHOP_GOODS_NO_EXIST);
        }
        //3.校验下单用户是否存在
        TradeUser user = userService.findOne(order.getUserId());
        if (user == null){
            CastException.cast(ShopCode.SHOP_USER_NO_EXIST);
        }
        //4.校验订单金额是否合法
//        if (order.getPayAmount().compareTo(goods.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()))) != 0){
        if (order.getGoodsPrice().compareTo(goods.getGoodsPrice()) != 0){
            CastException.cast(ShopCode.SHOP_GOODS_PRICE_INVALID);
        }
        //5.校验订单商品数量是否合法
        if (order.getGoodsNumber() >= goods.getGoodsNumber()){
            CastException.cast(ShopCode.SHOP_GOODS_NUM_NOT_ENOUGH);
        }
        log.info("校验订单通过");
    }


    /**
     * 生成预订单
     * @param order
     * @return
     */
    private Long savePreOrder(TradeOrder order){
        //1.设置订单状态不可见
        order.setOrderStatus(ShopCode.SHOP_ORDER_NO_CONFIRM.getCode());
        //2.设置订单id
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        //3.核算订单运费是否合法
        BigDecimal shippingFee = calculateShippinFee(order.getOrderAmount());
        if (order.getShippingFee().compareTo(shippingFee) != 0){
            CastException.cast(ShopCode.SHOP_ORDER_SHIPPINGFEE_INVALID);
        }
        //4.核算订单总金额是否合法
        BigDecimal orderAmount = order.getGoodsPrice().multiply(new BigDecimal(order.getGoodsNumber()));
        orderAmount.add(shippingFee);
        if (order.getOrderAmount().compareTo(orderAmount) != 0){
            CastException.cast(ShopCode.SHOP_ORDERAMOUNT_INVALID);
        }
        //5.判断用户是否使用余额
        BigDecimal moneyPaid = order.getMoneyPaid();
        if (moneyPaid != null){
            //5.1判断订单中余额是否合法
            int r = moneyPaid.compareTo(BigDecimal.ZERO);
            if (r == -1){ //余额小于0
                CastException.cast(ShopCode.SHOP_MONEY_PAID_LESS_ZERO);
            }
            if (r == 1){ //余额大于0
                TradeUser user = userService.findOne(order.getUserId());
                if (moneyPaid.compareTo(new BigDecimal(user.getUserMoney())) == 1){ //订单所需money大于用户所拥有余额
                    CastException.cast(ShopCode.SHOP_MONEY_PAID_INVALID);
                }
            }
        }else {
            order.setMoneyPaid(BigDecimal.ZERO);
        }
        //6.判断用户是否使用优惠券
        Long couponId = order.getCouponId();
        if (couponId != null){
            TradeCoupon coupon = couponService.findOne(couponId);
            //6.1判断优惠券是否存在
            if (coupon == null){
                CastException.cast(ShopCode.SHOP_COUPON_NO_EXIST);
            }
            //6.2判断优惠券是否已被使用
            if (coupon.getIsUsed().intValue() == ShopCode.SHOP_COUPON_ISUSED.getCode()){
                CastException.cast(ShopCode.SHOP_COUPON_ISUSED);
            }
        }else {
            order.setCouponPaid(BigDecimal.ZERO);
        }
        //7.核算订单支付金额[=订单总金额-余额-优惠券金额]
        BigDecimal payAmount = order.getOrderAmount().subtract(order.getMoneyPaid()).subtract(order.getCouponPaid());
        order.setPayAmount(payAmount);
        //8.设置下单时间
        order.setAddTime(new Date());
        //9.保存订单到数据库
        orderMapper.insert(order);
        //10.返回订单id
        return orderId;
    }

    /**
     * 核算运费
     * 【BigDecimal】https://baike.baidu.com/item/BigDecimal/5131707?fr=aladdin
     * @param orderAmount
     * @return
     */
    private BigDecimal calculateShippinFee(BigDecimal orderAmount) {
        //小于100不收运费;大于100收10
        if (orderAmount.compareTo(new BigDecimal(100)) == 1){
            return BigDecimal.ZERO;
        }else {
            return new BigDecimal(10);
        }
    }
}

2.10 sb集成junit测试下单流程

zk集群启动

dubbo-admin启动

image-20221208105901453

3 失败补偿机制(下单失败)

3.1 消息发送方

3.2 消息接收方

3.2.1 回退库存

3.2.2 回退优惠券

3.2.3 回退余额

3.2.4 取消订单

4 测试

标签:SHOP,RocketMQ2.5,BigDecimal,ShopCode,订单,CastException,下单,HM,order
From: https://www.cnblogs.com/yppah/p/16870256.html

相关文章