package co.yixiang.yshop.module.order.service.storeorder;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.yshop.framework.common.constant.ShopConstants;
import co.yixiang.yshop.framework.common.enums.OrderInfoEnum;
import co.yixiang.yshop.framework.common.enums.ShopCommonEnum;
import co.yixiang.yshop.framework.common.exception.ErrorCode;
import co.yixiang.yshop.module.cart.service.storecart.AppStoreCartService;
import co.yixiang.yshop.module.member.controller.app.user.vo.AppUserQueryVo;
import co.yixiang.yshop.module.member.dal.dataobject.user.MemberUserDO;
import co.yixiang.yshop.module.member.dal.dataobject.useraddress.UserAddressDO;
import co.yixiang.yshop.module.member.enums.BillDetailEnum;
import co.yixiang.yshop.module.member.service.user.MemberUserService;
import co.yixiang.yshop.module.member.service.useraddress.AppUserAddressService;
import co.yixiang.yshop.module.member.service.userbill.UserBillService;
import co.yixiang.yshop.module.message.enums.WechatTempateEnum;
import co.yixiang.yshop.module.message.mq.producer.WeixinNoticeProducer;
import co.yixiang.yshop.module.order.controller.app.order.param.AppComputeOrderParam;
import co.yixiang.yshop.module.order.controller.app.order.param.AppOrderParam;
import co.yixiang.yshop.module.order.controller.app.order.param.AppPayParam;
import co.yixiang.yshop.module.order.controller.app.order.vo.AppComputeVo;
import co.yixiang.yshop.module.order.controller.app.order.vo.AppConfirmOrderVo;
import co.yixiang.yshop.module.order.controller.app.order.vo.AppStoreOrderQueryVo;
import co.yixiang.yshop.module.order.convert.storeorder.StoreOrderConvert;
import co.yixiang.yshop.module.order.dal.dataobject.storeorder.StoreOrderDO;
import co.yixiang.yshop.module.order.dal.dataobject.storeordercartinfo.StoreOrderCartInfoDO;
import co.yixiang.yshop.module.order.dal.mysql.storeorder.StoreOrderMapper;
import co.yixiang.yshop.module.order.dal.redis.order.OrderRedisDAO;
import co.yixiang.yshop.module.order.enums.*;
import co.yixiang.yshop.module.order.service.storeorder.dto.*;
import co.yixiang.yshop.module.order.service.storeordercartinfo.StoreOrderCartInfoService;
import co.yixiang.yshop.module.order.service.storeorderstatus.StoreOrderStatusService;
import co.yixiang.yshop.module.pay.mq.producer.PayNoticeProducer;
import co.yixiang.yshop.module.product.controller.app.cart.vo.AppStoreCartQueryVo;
import co.yixiang.yshop.module.product.controller.app.product.vo.AppStoreProductRespVo;
import co.yixiang.yshop.module.product.dal.dataobject.shippingtemplates.ShippingTemplatesDO;
import co.yixiang.yshop.module.product.dal.dataobject.shippingtemplatesfree.ShippingTemplatesFreeDO;
import co.yixiang.yshop.module.product.dal.dataobject.shippingtemplatesregion.ShippingTemplatesRegionDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductreply.StoreProductReplyDO;
import co.yixiang.yshop.module.product.service.shippingtemplates.ShippingTemplatesService;
import co.yixiang.yshop.module.product.service.shippingtemplatesfree.ShippingTemplatesFreeService;
import co.yixiang.yshop.module.product.service.shippingtemplatesregion.ShippingTemplatesRegionService;
import co.yixiang.yshop.module.product.service.storeproduct.AppStoreProductService;
import co.yixiang.yshop.module.product.service.storeproductreply.AppStoreProductReplyService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.egzosn.pay.common.bean.RefundOrder;
import com.egzosn.pay.common.bean.RefundResult;
import com.egzosn.pay.spring.boot.core.PayServiceManager;
import com.egzosn.pay.spring.boot.core.bean.MerchantPayOrder;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.module.member.enums.ErrorCodeConstants.USER_ADDRESS_NOT_EXISTS;
import static co.yixiang.yshop.module.order.enums.ErrorCodeConstants.*;

/**
 * 订单 Service 实现类
 *
 * @author yshop
 */
@Slf4j
@Service
@Validated
public class AppStoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper,StoreOrderDO> implements AppStoreOrderService {

    @Resource
    private StoreOrderMapper storeOrderMapper;
    @Resource
    private AppStoreCartService appStoreCartService;
    @Resource
    private AppUserAddressService appUserAddressService;
    @Resource
    private ShippingTemplatesService shippingTemplatesService;
    @Resource
    private ShippingTemplatesRegionService shippingTemplatesRegionService;
    @Resource
    private ShippingTemplatesFreeService shippingTemplatesFreeService;
    @Resource
    private MemberUserService userService;
    @Resource
    private OrderRedisDAO orderRedisDAO;
    @Resource
    private AppStoreProductService appStoreProductService;
    @Resource
    private StoreOrderCartInfoService storeOrderCartInfoService;
    @Resource
    private StoreOrderStatusService storeOrderStatusService;
    @Resource
    private UserBillService billService;
    @Resource
    private AppStoreProductReplyService appStoreProductReplyService;
    @Resource
    private PayServiceManager manager;
    @Resource
    private WeixinNoticeProducer weixinNoticeProducer;
    @Resource
    private RedissonClient redissonClient;

    private static final String LOCK_KEY = "cart:check:stock:lock";
    private static final String STOCK_LOCK_KEY = "cart:do:stock:lock";



    /**
     * 返回订单确认数据
     *
     * @param uid  用户ID
     * @param cartIds 购物车id
     * @return ConfirmOrderVO
     */
    @Override
    public AppConfirmOrderVo confirmOrder(Long uid, String cartIds) {
        Map<String, Object> cartGroup = appStoreCartService.getUserProductCartList(uid,
                cartIds, ShopConstants.YSHOP_ONE_NUM);
        if (ObjectUtil.isNotEmpty(cartGroup.get("invalid"))) {
            throw exception(INVALID_PRODUCT);
        }
        if (ObjectUtil.isEmpty(cartGroup.get("valid"))) {
            throw exception(VALID_PRODUCT_EMPTY);
        }

        boolean deduction = false;
        boolean enableIntegral = true;

        //获取默认地址
        UserAddressDO userAddress = appUserAddressService.getOne(Wrappers.<UserAddressDO>lambdaQuery()
                .eq(UserAddressDO::getUid, uid)
                .eq(UserAddressDO::getIsDefault, ShopCommonEnum.DEFAULT_1.getValue()), false);

        List<AppStoreCartQueryVo> cartInfo = (List<AppStoreCartQueryVo>) cartGroup.get("valid");
        PriceGroupDto priceGroup = this.getOrderPriceGroup(cartInfo, userAddress);


        //缓存订单
        CacheDto cacheDTO = new CacheDto();
        cacheDTO.setCartInfo(cartInfo);
        cacheDTO.setPriceGroup(priceGroup);
        String cacheKey = orderRedisDAO.set(cacheDTO,uid);


        //获取用户信息
       AppUserQueryVo appUserQueryVo = userService.getAppUser(uid);

        return AppConfirmOrderVo.builder()
                .addressInfo(userAddress)
                .cartInfo(cartInfo)
                .priceGroup(priceGroup)
                .userInfo(appUserQueryVo)
                .orderKey(cacheKey)
                .deduction(deduction)
                .enableIntegral(enableIntegral)
                .build();

    }

    /**
     * 订单信息
     *
     * @param unique 唯一值或者单号
     * @param uid    用户id
     * @return YxStoreOrderQueryVo
     */
    @Override
    public AppStoreOrderQueryVo getOrderInfo(String unique, Long uid) {
        LambdaQueryWrapper<StoreOrderDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(
                i -> i.eq(StoreOrderDO::getOrderId, unique).or().eq(StoreOrderDO::getUnique, unique).or()
                        .eq(StoreOrderDO::getExtendOrderId, unique));
        if (uid != null) {
            wrapper.eq(StoreOrderDO::getUid, uid);
        }

        AppStoreOrderQueryVo appStoreOrderQueryVo = StoreOrderConvert.INSTANCE.convert1(storeOrderMapper.selectOne(wrapper));
        return appStoreOrderQueryVo;
    }



    /**
     * 计算订单价格
     *
     * @param uid     用户uid
     * @param key          订单缓存key
     * @param param 计算订单参数
     * @return map
     */
    @Override
    public Map<String, Object> computedOrder(Long uid, String key, AppComputeOrderParam param) {
        //检查订单
        Map<String,Object> map = this.check(uid,key,param);
        if (OrderLogEnum.EXTEND_ORDER.getValue().equals(map.get("status"))) {
            return map;
        }
        CacheDto cacheDTO = orderRedisDAO.get(key, uid);
        if (ObjectUtil.isNull(cacheDTO)) {
            throw exception(ORDER_EXPIRED);
        }
        BigDecimal payPrice = cacheDTO.getPriceGroup().getTotalPrice();


        //处理运费模板
        UserAddressDO userAddress = null;
        if (StrUtil.isNotBlank(param.getAddressId())) {
            userAddress = appUserAddressService.getById(param.getAddressId());
        }
        PriceGroupDto priceGroup = this.getOrderPriceGroup(cacheDTO.getCartInfo(), userAddress);
        BigDecimal payPostage = priceGroup.getStorePostage();

        payPrice = NumberUtil.add(payPrice, payPostage);


        //todo 优惠券
        BigDecimal couponPrice = BigDecimal.ZERO;

        // 积分抵扣 todo
        BigDecimal deductionPrice = BigDecimal.ZERO; //积分抵扣金额
        double usedIntegral = 0; //使用了多少积分

        if (payPrice.compareTo(BigDecimal.ZERO) <= 0) {
            payPrice = BigDecimal.ZERO;
        }

        AppComputeVo appComputeVo = AppComputeVo.builder()
                .totalPrice(cacheDTO.getPriceGroup().getTotalPrice())
                .payPrice(payPrice)
                .payPostage(payPostage)
                .couponPrice(couponPrice)
                .deductionPrice(deductionPrice)
                .usedIntegral(usedIntegral)
                .payIntegral(cacheDTO.getPriceGroup().getPayIntegral())
                .build();

        map.put("result", appComputeVo);
        map.put("status", OrderLogEnum.NONE_ORDER.getValue());

        return map;
    }

    /**
     * 创建订单
     *
     * @param uid 用户uid
     * @param key      key
     * @param param    param
     * @return YxStoreOrder
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Map<String, Object> createOrder(Long uid, String key, AppOrderParam param) {
        AppComputeOrderParam appComputeOrderParam = AppComputeOrderParam.builder()
                .addressId(param.getAddressId())
                .couponId(param.getCouponId())
                .useIntegral(param.getUseIntegral())
                .shippingType(param.getShippingType())
                .build();
        Map<String,Object> map = this.computedOrder(uid, key, appComputeOrderParam);

        if(!OrderLogEnum.NONE_ORDER.getValue().equals(map.get("status"))) {
            return map;
        }
        AppComputeVo computeVo = (AppComputeVo)map.get("result");
        if (StrUtil.isEmpty(param.getAddressId())) {
            throw exception(SELECT_ADDRESS);
        }
        UserAddressDO userAddress = appUserAddressService.getById(param.getAddressId());
        if (ObjectUtil.isNull(userAddress)) {
            throw exception(USER_ADDRESS_NOT_EXISTS);
        }

        Integer totalNum = 0;
        List<String> cartIds = new ArrayList<>();

        CacheDto cacheDTO = orderRedisDAO.get(key, uid);
        List<AppStoreCartQueryVo> cartInfo = cacheDTO.getCartInfo();

        //对库存检查加锁
        RLock lock = redissonClient.getLock(LOCK_KEY);
        if (lock.tryLock()){
            try {
                for (AppStoreCartQueryVo cart : cartInfo) {
                    //检测库存
                    appStoreCartService.checkProductStock(uid, cart.getProductId(), cart.getCartNum(), cart.getProductAttrUnique());

                    cartIds.add(cart.getId().toString());
                    totalNum += cart.getCartNum();
                }
            }catch (Exception ex) {
                log.error("[checkProductStock][执行异常]", ex);
                throw exception(new ErrorCode(999999,ex.getMessage()));
            } finally {
                lock.unlock();
            }
        }


        //计算奖励积分
        BigDecimal gainIntegral = this.getGainIntegral(cartInfo);
        //生成分布式唯一值
        String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
        //组合数据
        StoreOrderDO storeOrder = new StoreOrderDO();
        storeOrder.setUid(uid);
        storeOrder.setOrderId(orderSn);
        storeOrder.setRealName(userAddress.getRealName());
        storeOrder.setUserPhone(userAddress.getPhone());
        storeOrder.setUserAddress(userAddress.getProvince() + " " + userAddress.getCity() +
                " " + userAddress.getDistrict() + " " + userAddress.getDetail());
        storeOrder.setCartId(StrUtil.join(",", cartIds));
        storeOrder.setTotalNum(totalNum);
        storeOrder.setTotalPrice(computeVo.getTotalPrice());
        storeOrder.setTotalPostage(computeVo.getPayPostage());

        storeOrder.setCouponId(StrUtil.isBlank(param.getCouponId()) ? 0 : Integer.valueOf(param.getCouponId()));
        storeOrder.setCouponPrice(computeVo.getCouponPrice());
        storeOrder.setPayPrice(computeVo.getPayPrice());
        storeOrder.setPayPostage(computeVo.getPayPostage());
        storeOrder.setDeductionPrice(computeVo.getDeductionPrice());
        storeOrder.setPaid(OrderInfoEnum.PAY_STATUS_0.getValue());
        storeOrder.setPayType("");
        storeOrder.setUseIntegral(BigDecimal.valueOf(computeVo.getUsedIntegral()));
        storeOrder.setBackIntegral(BigDecimal.ZERO);
        storeOrder.setGainIntegral(gainIntegral);
        storeOrder.setMark(param.getMark());
        storeOrder.setCost(cacheDTO.getPriceGroup().getCostPrice());
        storeOrder.setUnique(key);
        storeOrder.setShippingType(OrderInfoEnum.SHIPPIING_TYPE_1.getValue());

        boolean res = this.save(storeOrder);
        if (!res) {
            throw exception(ORDER_GEN_FAIL);
        }

        // 减库存加销量
        this.deStockIncSale(cartInfo);


        //保存购物车商品信息，异步执行
        storeOrderCartInfoService.saveCartInfo(storeOrder.getId(), storeOrder.getOrderId(),cartInfo);


        //购物车状态修改异步执行
        appStoreCartService.updateCartPayStatus(cartIds);


        //删除缓存
        orderRedisDAO.delete(key,uid);

        //增加状态
        storeOrderStatusService.create(uid,storeOrder.getId(), OrderLogEnum.CREATE_ORDER.getValue(),
                OrderLogEnum.CREATE_ORDER.getDesc());


        //加入延时队列，30分钟自动取消
        try {
            RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(ShopConstants.REDIS_ORDER_OUTTIME_UNPAY_QUEUE);
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
            delayedQueue.offer(orderSn, ShopConstants.ORDER_OUTTIME_UNPAY, TimeUnit.MINUTES);
            String s = TimeUnit.SECONDS.toSeconds(ShopConstants.ORDER_OUTTIME_UNPAY) + "分钟";
            log.info("添加延时队列成功 ，延迟时间：" + s);
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        OrderExtendDto orderDTO = new OrderExtendDto();
        orderDTO.setKey(key);
        orderDTO.setOrderId(storeOrder.getOrderId());
        map.put("status", OrderLogEnum.CREATE_ORDER_SUCCESS.getValue());
        map.put("result", orderDTO);
        map.put("createTime", storeOrder.getCreateTime());


        return map;
    }

    /**
     * 第三方支付
     * @param uid  用户id
     * @param param 订单参数
     * @return
     */
    @Override
    public Map<String, Object> pay(Long uid, AppPayParam param) {
        AppStoreOrderQueryVo orderInfo = getOrderInfo(param.getUni(), uid);
        if (ObjectUtil.isNull(orderInfo)) {
            throw exception(STORE_ORDER_NOT_EXISTS);
        }
        if(orderInfo.getPaid().equals(OrderInfoEnum.PAY_STATUS_1.getValue())) {
            throw exception(ORDER_PAY_FINISH);
        }

        MemberUserDO memberUserDO = userService.getUser(uid);
        Map<String, Object> map = new LinkedHashMap<>();
        switch (PayTypeEnum.toType(param.getPaytype())){
            case WEIXIN:
                if(AppFromEnum.WEIXIN_H5.getValue().equals(param.getFrom())){
                    MerchantPayOrder payOrder = new MerchantPayOrder("3", "MWEB", "h5商品购买",
                            "h5商品购买", orderInfo.getPayPrice(), param.getUni());
                    map.put("data",manager.getOrderInfo(payOrder));
                } else if(AppFromEnum.ROUNTINE.getValue().equals(param.getFrom())){
                    MerchantPayOrder payOrder = new MerchantPayOrder("3", "JSAPI", "小程序商品购买",
                            "小程序商品购买", orderInfo.getPayPrice(), param.getUni());
                    payOrder.setOpenid(memberUserDO.getWxProfile().getRoutineOpenid());
                    map.put("data",manager.getOrderInfo(payOrder));

                }else if(AppFromEnum.APP.getValue().equals(param.getFrom())){
                    //app支付
                    MerchantPayOrder payOrder = new MerchantPayOrder("3", "APP", "APP商品购买",
                            "APP5商品购买", orderInfo.getPayPrice(), param.getUni());
                    map.put("data",manager.getOrderInfo(payOrder));

                }else{//公众号
                    //detailId 是后台数据库添加当服务商id
                    MerchantPayOrder payOrder = new MerchantPayOrder("3", "JSAPI", "公众号商品购买",
                            "公众号商品购买", orderInfo.getPayPrice(), param.getUni());
                    payOrder.setOpenid(memberUserDO.getWxProfile().getOpenid());
                    map.put("data",manager.getOrderInfo(payOrder));
                }
                break;
            case YUE:
                this.yuePay(param.getUni(), uid);
                map.put("status","ok");
                break;
            case ALI:
                //小程序支付
                MerchantPayOrder payOrder = new MerchantPayOrder("1", "MINAPP", "小程序商品购买",
                        "小程序商品购买", orderInfo.getPayPrice(), param.getUni());
               // payOrder.setOpenid(memberUserDO.getWxProfile().getOpenid());
                map.put("data",manager.getOrderInfo(payOrder));

            default:
        }
        return map;
    }

    /**
     * 余额支付
     *
     * @param orderId 订单号
     * @param uid     用户id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void yuePay(String orderId, Long uid) {
        AppStoreOrderQueryVo orderInfo = getOrderInfo(orderId, uid);
        if (ObjectUtil.isNull(orderInfo)) {
            throw exception(STORE_ORDER_NOT_EXISTS);
        }

        if (OrderInfoEnum.PAY_STATUS_1.getValue().equals(orderInfo.getPaid())) {
            throw exception(ORDER_PAY_FINISH);
        }

        AppUserQueryVo userInfo = userService.getAppUser(uid);

        if (userInfo.getNowMoney().compareTo(orderInfo.getPayPrice()) < 0) {
            throw exception(PAY_YUE_NOT);
        }

        userService.decPrice(uid, orderInfo.getPayPrice());

        //支付成功后处理
        this.paySuccess(orderInfo.getOrderId(), PayTypeEnum.YUE.getValue());
    }


    /**
     * 支付成功后操作
     *
     * @param orderId 订单号
     * @param payType 支付方式
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void paySuccess(String orderId, String payType) {
        AppStoreOrderQueryVo orderInfo = getOrderInfo(orderId, null);

        //更新订单状态
        LambdaQueryWrapper<StoreOrderDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrderDO::getOrderId, orderId);
        StoreOrderDO storeOrder = new StoreOrderDO();
        storeOrder.setPaid(OrderInfoEnum.PAY_STATUS_1.getValue());
        storeOrder.setPayType(payType);
        storeOrder.setPayTime(LocalDateTime.now());
        this.update(storeOrder, wrapper);

        //增加用户购买次数
        userService.incPayCount(orderInfo.getUid());
        //增加状态
        storeOrderStatusService.create(orderInfo.getUid(),orderInfo.getId(), OrderLogEnum.PAY_ORDER_SUCCESS.getValue(),
                OrderLogEnum.PAY_ORDER_SUCCESS.getDesc());


        MemberUserDO userInfo = userService.getUser(orderInfo.getUid());
        //增加流水
        String payTypeMsg = PayTypeEnum.WEIXIN.getDesc();
        if (PayTypeEnum.YUE.getValue().equals(payType)) {
            payTypeMsg = PayTypeEnum.YUE.getDesc();
        }else if (PayTypeEnum.ALI.getValue().equals(payType)) {
            payTypeMsg = PayTypeEnum.ALI.getDesc();
        }
        billService.expend(userInfo.getId(), "购买商品",
                BillDetailEnum.CATEGORY_1.getValue(),
                BillDetailEnum.TYPE_3.getValue(),
                orderInfo.getPayPrice().doubleValue(), userInfo.getNowMoney().doubleValue(),
                payTypeMsg + orderInfo.getPayPrice() + "元购买商品");

        //发送消息队列进行推送消息
        if(userInfo.getLoginType().equals(AppFromEnum.ROUNTINE.getValue())){
            weixinNoticeProducer.sendNoticeMessage(orderInfo.getUid(),WechatTempateEnum.PAY_SUCCESS.getValue(),
                    WechatTempateEnum.SUBSCRIBE.getValue(),orderId,
                    orderInfo.getPayPrice().toString(),"","","");
        }else if(userInfo.getLoginType().equals(AppFromEnum.WECHAT.getValue())){
            weixinNoticeProducer.sendNoticeMessage(orderInfo.getUid(),WechatTempateEnum.PAY_SUCCESS.getValue(),
                    WechatTempateEnum.TEMPLATES.getValue(),orderId,
                    orderInfo.getPayPrice().toString(),"","","");
        }


    }

    /**
     * 减库存增加销量
     *
     * @param cartInfo 购物车
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deStockIncSale(List<AppStoreCartQueryVo> cartInfo) {
        log.info("========减库存增加销量start=========");
        //对库存加锁
        RLock lock = redissonClient.getLock(STOCK_LOCK_KEY);
        if (lock.tryLock()) {
            try {
                for (AppStoreCartQueryVo storeCartVO : cartInfo) {
                    appStoreProductService.decProductStock(storeCartVO.getCartNum(), storeCartVO.getProductId(),
                            storeCartVO.getProductAttrUnique(), 0L, "");
                }
            }catch (Exception ex) {
                log.error("[deStockIncSale][执行异常]", ex);
                throw exception(new ErrorCode(999999,ex.getMessage()));
            } finally {
                lock.unlock();
            }
        }
    }


    /**
     * 订单列表
     *
     * @param uid   用户id
     * @param type  OrderStatusEnum
     * @param page  page
     * @param limit limit
     * @return list
     */
    @Override
    public List<AppStoreOrderQueryVo> orderList(Long uid, int type, int page, int limit) {
        LambdaQueryWrapper<StoreOrderDO> wrapper = new LambdaQueryWrapper<>();
        if (uid != null) {
            wrapper.eq(StoreOrderDO::getUid, uid);
        }
        wrapper.orderByDesc(StoreOrderDO::getId);


        switch (OrderStatusEnum.toType(type)) {
            case STATUS__1:
                break;
            //未支付
            case STATUS_0:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_0.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_0.getValue())
                        .eq(StoreOrderDO::getStatus, OrderInfoEnum.STATUS_0.getValue());
                break;
            //待发货
            case STATUS_1:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_0.getValue())
                        .eq(StoreOrderDO::getStatus, OrderInfoEnum.STATUS_0.getValue());
                break;
            //待收货
            case STATUS_2:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_0.getValue())
                        .eq(StoreOrderDO::getStatus, OrderInfoEnum.STATUS_1.getValue());
                break;
            //待评价
            case STATUS_3:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_0.getValue())
                        .eq(StoreOrderDO::getStatus, OrderInfoEnum.STATUS_2.getValue());
                break;
            //已完成
            case STATUS_4:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_0.getValue())
                        .eq(StoreOrderDO::getStatus, OrderInfoEnum.STATUS_3.getValue());
                break;
            //退款中
            case STATUS_MINUS_1:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_1.getValue());
                break;
            //已退款
            case STATUS_MINUS_2:
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_0.getValue())
                        .eq(StoreOrderDO::getRefundStatus, OrderInfoEnum.REFUND_STATUS_2.getValue());
                break;
            //退款
            case STATUS_MINUS_3:
                String[] strs = {"1", "2"};
                wrapper.eq(StoreOrderDO::getPaid, OrderInfoEnum.PAY_STATUS_1.getValue())
                        .in(StoreOrderDO::getRefundStatus, Arrays.asList(strs));
                break;
            default:
        }

        Page<StoreOrderDO> pageModel = new Page<>(page, limit);
        IPage<StoreOrderDO> pageList = storeOrderMapper.selectPage(pageModel, wrapper);
        List<AppStoreOrderQueryVo> list = StoreOrderConvert.INSTANCE.convertList01(pageList.getRecords());

        return list.stream().map(this::handleOrder).collect(Collectors.toList());

    }


    /**
     * 处理订单返回的状态
     *
     * @param order order
     * @return YxStoreOrderQueryVo
     */
    @Override
    public AppStoreOrderQueryVo handleOrder(AppStoreOrderQueryVo order) {
        LambdaQueryWrapper<StoreOrderCartInfoDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreOrderCartInfoDO::getOid, order.getId());
        List<StoreOrderCartInfoDO> cartInfos = storeOrderCartInfoService.list(wrapper);

        List<AppStoreCartQueryVo> cartInfo = cartInfos.stream()
                .map(cart -> {
                    AppStoreCartQueryVo cartQueryVo = JSON.parseObject(cart.getCartInfo(), AppStoreCartQueryVo.class);
                    cartQueryVo.setUnique(cart.getUnique());
                    cartQueryVo.setIsReply(appStoreProductReplyService.replyCount(cart.getUnique()));
                    return cartQueryVo;
                })
                .collect(Collectors.toList());
        order.setCartInfo(cartInfo);

        StatusDto statusDTO = new StatusDto();
        if (OrderStatusEnum.STATUS_0.getValue().equals(order.getPaid())) {
            //计算未支付到自动取消订 时间
            int offset = Integer.valueOf(String.valueOf(ShopConstants.ORDER_OUTTIME_UNPAY));
            Date time = DateUtil.offsetMinute(order.getCreateTime(), offset);
            statusDTO.set_class("nobuy");
            statusDTO.set_msg(StrUtil.format("请在{}前完成支付", DateUtil.formatDateTime(time)));
            statusDTO.set_type("0");
            statusDTO.set_title("未支付");
        } else if (OrderInfoEnum.REFUND_STATUS_1.getValue().equals(order.getRefundStatus())) {
            statusDTO.set_class("state-sqtk");
            statusDTO.set_msg("商家审核中,请耐心等待");
            statusDTO.set_type("-1");
            statusDTO.set_title("申请退款中");
        } else if (OrderInfoEnum.REFUND_STATUS_2.getValue().equals(order.getRefundStatus())) {
            statusDTO.set_class("state-sqtk");
            statusDTO.set_msg("已为您退款,感谢您的支持");
            statusDTO.set_type("-2");
            statusDTO.set_title("已退款");
        } else if (OrderInfoEnum.STATUS_0.getValue().equals(order.getStatus())) {
            // 拼团 todo
            if (order.getPinkId() > 0) {
            } else {
                statusDTO.set_class("state-nfh");
                statusDTO.set_msg("商家未发货,请耐心等待");
                statusDTO.set_type("1");
                statusDTO.set_title("未发货");
            }

        } else if (OrderInfoEnum.STATUS_1.getValue().equals(order.getStatus())) {
            statusDTO.set_class("state-ysh");
            statusDTO.set_msg("服务商已发货");
            statusDTO.set_type("2");
            statusDTO.set_title("待收货");
        } else if (OrderInfoEnum.STATUS_2.getValue().equals(order.getStatus())) {
            statusDTO.set_class("state-ypj");
            statusDTO.set_msg("已收货,快去评价一下吧");
            statusDTO.set_type("3");
            statusDTO.set_title("待评价");
        } else if (OrderInfoEnum.STATUS_3.getValue().equals(order.getStatus())) {
            statusDTO.set_class("state-ytk");
            statusDTO.set_msg("交易完成,感谢您的支持");
            statusDTO.set_type("4");
            statusDTO.set_title("交易完成");
        }

        if (PayTypeEnum.WEIXIN.getValue().equals(order.getPayType())) {
            statusDTO.set_payType("微信支付");
        } else if (PayTypeEnum.YUE.getValue().equals(order.getPayType())) {
            statusDTO.set_payType("余额支付");
        } else {
            statusDTO.set_payType("积分支付");
        }

        order.set_status(statusDTO);


        return order;
    }


    /**
     * 订单确认收货
     *
     * @param orderId 单号
     * @param uid     uid
     */
    @Override
    public void takeOrder(String orderId, Long uid) {
        AppStoreOrderQueryVo order = this.getOrderInfo(orderId, uid);
        if (ObjectUtil.isNull(order)) {
            throw exception(STORE_ORDER_NOT_EXISTS);
        }
        order = handleOrder(order);
        if (!OrderStatusEnum.STATUS_2.getValue().toString().equals(order.get_status().get_type())) {
            throw exception(ORDER_STATUS_ERROR);
        }

        StoreOrderDO storeOrder = new StoreOrderDO();
        storeOrder.setStatus(OrderInfoEnum.STATUS_2.getValue());
        storeOrder.setId(order.getId());
        this.updateById(storeOrder);

        //增加状态
        storeOrderStatusService.create(order.getUid(),order.getId(), OrderLogEnum.TAKE_ORDER_DELIVERY.getValue(), OrderLogEnum.TAKE_ORDER_DELIVERY.getDesc());

        //奖励积分
        this.gainUserIntegral(order);

        //分销计算 todo

    }


    /**
     * 订单评价
     *
     * @param uid          用户ID
     * @param unique        订单orderCart唯一值
     * @param comment       评论内容
     * @param pics          图片
     * @param productScore  评分
     * @param serviceScore  评分
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void orderComment(Long uid, String unique, String comment, String pics, String productScore,
                             String serviceScore) {
        StoreOrderCartInfoDO orderCartInfo = storeOrderCartInfoService
                .getOne(Wrappers.<StoreOrderCartInfoDO>lambdaQuery()
                        .eq(StoreOrderCartInfoDO::getUnique,unique));
        
        if (ObjectUtil.isEmpty(orderCartInfo)) {
            throw exception(COMMENT_PRODUCT_NOT_EXISTS);
        }

        Long count = appStoreProductReplyService.count(Wrappers.<StoreProductReplyDO>lambdaQuery()
                .eq(StoreProductReplyDO::getOid, orderCartInfo.getOid())
                .eq(StoreProductReplyDO::getProductId, orderCartInfo.getProductId()));
        if (count > 0) {
            throw exception(COMMENT_PRODUCT_IN_EXISTS);
        }


        StoreProductReplyDO storeProductReply = StoreProductReplyDO.builder()
                .uid(uid)
                .oid(orderCartInfo.getOid())
                .productId(orderCartInfo.getProductId())
                .productScore(Integer.valueOf(productScore))
                .serviceScore(Integer.valueOf(serviceScore))
                .comment(comment)
                .pics(pics)
                .unique(unique)
                .build();

        appStoreProductReplyService.save(storeProductReply);
        //获取评价商品数量
        Long replyCount = appStoreProductReplyService.count(new LambdaQueryWrapper<StoreProductReplyDO>().eq(StoreProductReplyDO::getOid, orderCartInfo.getOid()));
        //购买商品数量
        Long cartCount = storeOrderCartInfoService.count(new LambdaQueryWrapper<StoreOrderCartInfoDO>().eq(StoreOrderCartInfoDO::getOid, orderCartInfo.getOid()));

        if (NumberUtil.equals(replyCount,cartCount)) {
            StoreOrderDO storeOrder = new StoreOrderDO();
            storeOrder.setStatus(OrderInfoEnum.STATUS_3.getValue());
            storeOrder.setId(orderCartInfo.getOid());
            this.updateById(storeOrder);
        }
        //增加状态
        storeOrderStatusService.create(uid,orderCartInfo.getOid(),
                OrderLogEnum.EVAL_ORDER.getValue(),
                OrderLogEnum.EVAL_ORDER.getDesc());
    }

    /**
     * 删除订单
     *
     * @param orderId 单号
     * @param uid     uid
     */
    @Override
    public void removeOrder(String orderId, Long uid) {
        AppStoreOrderQueryVo order = this.getOrderInfo(orderId,  uid);
        if (order == null) {
            throw exception(STORE_ORDER_NOT_EXISTS);
        }
        order = handleOrder(order);
        if (!OrderInfoEnum.STATUS_3.getValue().equals(order.getStatus())) {
            throw exception(ORDER_NOT_DELETE);
        }

        this.removeById(order.getId());

        //增加状态
        storeOrderStatusService.create(uid,order.getId(),
                OrderLogEnum.REMOVE_ORDER.getValue(),
                OrderLogEnum.REMOVE_ORDER.getDesc());
    }

    /**
     * 未付款取消订单
     *
     * @param orderId 订单号
     * @param uid     用户id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void cancelOrder(String orderId, Long uid) {
        log.info("订单取消：({})",orderId);
        AppStoreOrderQueryVo order = this.getOrderInfo(orderId, uid);
        if (ObjectUtil.isNull(order)) {
            throw exception(STORE_ORDER_NOT_EXISTS);
        }
        if (order.getPaid() != 0) {
            throw exception(ORDER_NOT_CANCEL);
        }

        this.regressionIntegral(order, 0);

        this.regressionStock(order, 0);

        this.regressionCoupon(order, 0);

        storeOrderMapper.deleteById(order.getId());
    }

    /**
     * 确认订单退款
     *
     * @param orderId 单号
     * @param price   金额
     */
    @Override
    public void orderRefund(String orderId, BigDecimal price) {

        AppStoreOrderQueryVo orderQueryVo = getOrderInfo(orderId, null);

        StoreOrderDO storeOrder = new StoreOrderDO();
        //修改状态
        storeOrder.setId(orderQueryVo.getId());

        //根据支付类型不同退款不同
        if (PayTypeEnum.YUE.getValue().equals(orderQueryVo.getPayType())) {
            storeOrder.setRefundStatus(OrderInfoEnum.REFUND_STATUS_2.getValue());
            storeOrder.setRefundPrice(price);
            this.baseMapper.updateById(storeOrder);
            //退款到余额
            userService.incMoney(orderQueryVo.getUid(), price);
            MemberUserDO memberUserDO = userService.getById(orderQueryVo.getUid());

            //增加流水
            billService.income(orderQueryVo.getUid(), "商品退款", BillDetailEnum.CATEGORY_1.getValue(),
                    BillDetailEnum.TYPE_5.getValue(),
                    price.doubleValue(),
                    NumberUtil.add(price, memberUserDO.getNowMoney()).doubleValue(),
                    "订单退款到余额" + price + "元", orderQueryVo.getId().toString());
            //退款得仅仅退库存，其他得 不退比如优惠券等
            this.regressionStock(orderQueryVo, 1);

            storeOrderStatusService.create(orderQueryVo.getUid(),orderQueryVo.getId(),
                    OrderLogEnum.REFUND_ORDER_SUCCESS.getValue(), "退款给用户：" + price + "元");


        } else{
           //生成退款单号
            String refundNo = IdUtil.getSnowflake(0,0).nextIdStr();;
            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setDescription("商品退款");
            refundOrder.setOrderDate(new Date());
            refundOrder.setRefundAmount(price);
            refundOrder.setRefundNo(refundNo);
            refundOrder.setTotalAmount(orderQueryVo.getTotalPrice());
            refundOrder.setOutTradeNo(orderQueryVo.getOrderId());
            RefundResult refundResult = null;
            if(PayTypeEnum.WEIXIN.getValue().equals(orderQueryVo.getPayType())) {
                // 微信
                refundResult = manager.refund("3", refundOrder);

            }else if(PayTypeEnum.ALI.getValue().equals(orderQueryVo.getPayType())){
                //支付宝
                refundResult = manager.refund("1", refundOrder);
            }
            //退款成功操作
            if(refundResult.getResultCode() == "SUCCESS" || refundResult.getMsg() == "Success"){
                storeOrder.setRefundStatus(OrderInfoEnum.REFUND_STATUS_2.getValue());
                storeOrder.setRefundPrice(price);
                this.baseMapper.updateById(storeOrder);
                //退款得仅仅退库存，其他得 不退比如优惠券等
                this.regressionStock(orderQueryVo, 1);
                storeOrderStatusService.create(orderQueryVo.getUid(),orderQueryVo.getId(),
                        OrderLogEnum.REFUND_ORDER_SUCCESS.getValue(), "退款给用户：" + price + "元");
            }

        }





    }


    /**
     * 退回积分
     *
     * @param order 订单
     */
    private void regressionIntegral(AppStoreOrderQueryVo order, Integer type) {
        if (type == 0) {
            if (OrderInfoEnum.PAY_STATUS_1.getValue().equals(order.getPaid())
                    || OrderStatusEnum.STATUS_MINUS_2.getValue().equals(order.getStatus())) {
                return;
            }
        } else {
            if (!(OrderInfoEnum.PAY_STATUS_1.getValue().equals(order.getPaid())
                    && OrderInfoEnum.REFUND_STATUS_2.getValue().equals(order.getRefundStatus()))) {
                return;
            }
        }

        if (order.getPayIntegral().compareTo(BigDecimal.ZERO) > 0) {
            order.setUseIntegral(order.getPayIntegral());
        }
        if (order.getUseIntegral().compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }

        if (!OrderStatusEnum.STATUS_MINUS_2.getValue().equals(order.getStatus())
                && !OrderInfoEnum.REFUND_STATUS_2.getValue().equals(order.getRefundStatus())
                && order.getBackIntegral().compareTo(BigDecimal.ZERO) > 0) {
            return;
        }

        MemberUserDO yxUser = userService.getById(order.getUid());

        //增加积分
        BigDecimal newIntegral = NumberUtil.add(order.getUseIntegral(), yxUser.getIntegral());
        yxUser.setIntegral(newIntegral);
        userService.updateById(yxUser);

        //增加流水
        billService.income(yxUser.getId(), "积分回退", BillDetailEnum.CATEGORY_2.getValue(),
                BillDetailEnum.TYPE_8.getValue(),
                order.getUseIntegral().doubleValue(),
                newIntegral.doubleValue(),
                "购买商品失败,回退积分" + order.getUseIntegral(), order.getId().toString());

        //更新回退积分
        StoreOrderDO storeOrder = new StoreOrderDO();
        storeOrder.setBackIntegral(order.getUseIntegral());
        storeOrder.setId(order.getId());
        this.updateById(storeOrder);
    }

    /**
     * 退回优惠券
     *
     * @param order 订单 todo
     */
    private void regressionCoupon(AppStoreOrderQueryVo order, Integer type) {
    }

    /**
     * 退回库存
     *
     * @param order 订单
     */
    private void regressionStock(AppStoreOrderQueryVo order, Integer type) {
        if (type == 0) {
            if (OrderInfoEnum.PAY_STATUS_1.getValue().equals(order.getPaid())
                    || OrderStatusEnum.STATUS_MINUS_2.getValue().equals(order.getStatus())) {
                return;
            }
        } else {
            if (!(OrderInfoEnum.PAY_STATUS_1.getValue().equals(order.getPaid())
                    && OrderInfoEnum.REFUND_STATUS_2.getValue().equals(order.getRefundStatus()))) {
                return;
            }
        }
        LambdaQueryWrapper<StoreOrderCartInfoDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(StoreOrderCartInfoDO::getCartId, Arrays.asList(order.getCartId().split(",")));

        List<StoreOrderCartInfoDO> cartInfoList = storeOrderCartInfoService.list(wrapper);
        for (StoreOrderCartInfoDO cartInfo : cartInfoList) {
            AppStoreCartQueryVo cart = JSONObject.parseObject(cartInfo.getCartInfo()
                    , AppStoreCartQueryVo.class);
            appStoreProductService.incProductStock(cart.getCartNum(), cart.getProductId()
                    , cart.getProductAttrUnique(), 0L, null);

        }
    }
    

    /**
     * 奖励积分
     *
     * @param order 订单
     */
    private void gainUserIntegral(AppStoreOrderQueryVo order) {
        if (order.getGainIntegral().compareTo(BigDecimal.ZERO) > 0) {
            MemberUserDO user = userService.getUser(order.getUid());

            BigDecimal newIntegral = NumberUtil.add(user.getIntegral(), order.getGainIntegral());
            user.setIntegral(newIntegral);
            user.setId(order.getUid());
            userService.updateById(user);

            //增加流水
            billService.income(user.getId(), "购买商品赠送积分", BillDetailEnum.CATEGORY_2.getValue(),
                    BillDetailEnum.TYPE_9.getValue(),
                    order.getGainIntegral().doubleValue(),
                    newIntegral.doubleValue(),
                    "购买商品赠送" + order.getGainIntegral() + "积分", order.getId().toString());
        }
    }



    /**
     * 计算奖励的积分
     *
     * @param cartInfo cartInfo
     * @return double
     */
    private BigDecimal getGainIntegral(List<AppStoreCartQueryVo> cartInfo) {
        BigDecimal gainIntegral = BigDecimal.ZERO;
        for (AppStoreCartQueryVo cart : cartInfo) {
            if (cart.getCombinationId() > 0 || cart.getSeckillId() > 0 || cart.getBargainId() > 0) {
                continue;
            }
            BigDecimal cartInfoGainIntegral = BigDecimal.ZERO;
            Double gain = cart.getProductInfo().getGiveIntegral().doubleValue();
            if (gain > 0) {
                cartInfoGainIntegral = NumberUtil.round(NumberUtil.mul(cart.getCartNum(), gain), 2);
            }
            gainIntegral = NumberUtil.add(gainIntegral, cartInfoGainIntegral);
        }
        return gainIntegral;
    }



    /**
     * 订单检测
     * @param uid uid
     * @param key 缓存值
     * @param param ComputeOrderParam
     * @return map
     */
    private Map<String,Object> check(Long uid,String key, AppComputeOrderParam param){
        Map<String,Object> map = Maps.newHashMap();
        if(StrUtil.isBlank(key)) {
            throw exception(PARAM_ERROR);
        }
        AppStoreOrderQueryVo storeOrder = this.getOrderInfo(key,uid);
        if(ObjectUtil.isNotNull(storeOrder)){

            OrderExtendDto orderExtendDTO = OrderExtendDto.builder()
                    .key(key)
                    .orderId(storeOrder.getOrderId())
                    .build();
            map.put("status", OrderLogEnum.EXTEND_ORDER.getValue());
            map.put("result", orderExtendDTO);
            map.put("msg",OrderLogEnum.EXTEND_ORDER.getDesc());
        }


        return map;
    }



    /**
     * 获取订单价格
     *
     * @param cartInfo 购物车列表
     * @return PriceGroupDto
     */
    private PriceGroupDto getOrderPriceGroup(List<AppStoreCartQueryVo> cartInfo, UserAddressDO userAddress) {

        BigDecimal storePostage = BigDecimal.ZERO;

        BigDecimal storeFreePostage = BigDecimal.ZERO;

        BigDecimal totalPrice = this.getOrderSumPrice(cartInfo, "truePrice");//获取订单总金额
        BigDecimal costPrice = this.getOrderSumPrice(cartInfo, "costPrice");//获取订单成本价
        BigDecimal payIntegral = this.getOrderSumPrice(cartInfo, "payIntegral");//获取订单需要的积分

        //运费模板
        storePostage = this.handlePostage(cartInfo, userAddress);

        PriceGroupDto priceGroupDTO = new PriceGroupDto();
        priceGroupDTO.setStorePostage(storePostage);
        priceGroupDTO.setStoreFreePostage(storeFreePostage);
        priceGroupDTO.setTotalPrice(totalPrice);
        priceGroupDTO.setCostPrice(costPrice);
        priceGroupDTO.setPayIntegral(payIntegral);
        return priceGroupDTO;
    }

    /**
     * 获取某字段价格
     *
     * @param cartInfo 购物车
     * @param key      key值
     * @return Double
     */
    private BigDecimal getOrderSumPrice(List<AppStoreCartQueryVo> cartInfo, String key) {
        BigDecimal sumPrice = BigDecimal.ZERO;

        if ("truePrice".equals(key)) {
            for (AppStoreCartQueryVo storeCart : cartInfo) {
                sumPrice = NumberUtil.add(sumPrice, NumberUtil.mul(storeCart.getCartNum(), storeCart.getTruePrice()));
            }
        } else if ("costPrice".equals(key)) {
            for (AppStoreCartQueryVo storeCart : cartInfo) {
                sumPrice = NumberUtil.add(sumPrice,
                        NumberUtil.mul(storeCart.getCartNum(), storeCart.getCostPrice()));
            }
        } else if ("payIntegral".equals(key)) {
            for (AppStoreCartQueryVo storeCart : cartInfo) {
                if (storeCart.getProductInfo().getAttrInfo() != null && storeCart.getProductInfo().getAttrInfo().getIntegral() != null) {
                    sumPrice = NumberUtil.add(sumPrice,
                            NumberUtil.mul(storeCart.getCartNum(), storeCart.getProductInfo().getAttrInfo().getIntegral()));
                }

            }
        }

        return sumPrice;
    }


    /**
     * 根据运费模板算法返回邮费
     *
     * @param cartInfo    购物车
     * @param userAddress 地址
     * @return double
     */
    private BigDecimal handlePostage(List<AppStoreCartQueryVo> cartInfo, UserAddressDO userAddress) {
        BigDecimal storePostage = BigDecimal.ZERO;
        if (userAddress != null) {
            if (userAddress.getCityId() == null) {
                return storePostage;
            }
            //城市包括默认
            int cityId = userAddress.getCityId();
            List<Integer> citys = new ArrayList<>();
            citys.add(cityId);
            citys.add(0);

            List<AppStoreProductRespVo> storeProductVOList = cartInfo
                    .stream()
                    .map(AppStoreCartQueryVo::getProductInfo)
                    .collect(Collectors.toList());
            List<Integer> tempIdS = storeProductVOList
                    .stream()
                    .map(AppStoreProductRespVo::getTempId)
                    .collect(Collectors.toList());


            //获取商品用到的运费模板
            List<ShippingTemplatesDO> shippingTemplatesList = shippingTemplatesService
                    .list(Wrappers.<ShippingTemplatesDO>lambdaQuery()
                            .in(ShippingTemplatesDO::getId, tempIdS));
            //获取运费模板区域列表按照城市排序
            List<ShippingTemplatesRegionDO> shippingTemplatesRegionList = shippingTemplatesRegionService
                    .list(Wrappers.<ShippingTemplatesRegionDO>lambdaQuery()
                            .in(ShippingTemplatesRegionDO::getTempId, tempIdS)
                            .in(ShippingTemplatesRegionDO::getCityId, citys)
                            .orderByAsc(ShippingTemplatesRegionDO::getCityId));
            //提取运费模板类型
            Map<Integer, Integer> shippingTemplatesMap = shippingTemplatesList
                    .stream()
                    .collect(Collectors.toMap(ShippingTemplatesDO::getId,
                            ShippingTemplatesDO::getType));
            //提取运费模板有相同值覆盖
            Map<Integer, ShippingTemplatesRegionDO> shippingTemplatesRegionMap =
                    shippingTemplatesRegionList.stream()
                            .collect(Collectors.toMap(ShippingTemplatesRegionDO::getTempId,
                                    ShippingTemplatesRegionDO -> ShippingTemplatesRegionDO,
                                    (key1, key2) -> key2));


            Map<Integer, TemplateDto> templateDTOMap = new HashMap<>();
            for (AppStoreCartQueryVo storeCartVO : cartInfo) {
                Integer tempId = storeCartVO.getProductInfo().getTempId();

                //是否是固定邮费,没设置运费模板走固定
                if (tempId == 0) {
                    return storeCartVO.getProductInfo().getPostage();
                }

                //根据模板类型获取相应的数量
                double num = 0d;
                if (ShippingTempEnum.TYPE_1.getValue().equals(shippingTemplatesMap.get(tempId))) {
                    num = storeCartVO.getCartNum().doubleValue();
                } else if (ShippingTempEnum.TYPE_2.getValue().equals(shippingTemplatesMap.get(tempId))) {
                    num = NumberUtil.mul(storeCartVO.getCartNum(),
                            storeCartVO.getProductInfo().getAttrInfo().getWeight()).doubleValue();
                } else if (ShippingTempEnum.TYPE_3.getValue().equals(shippingTemplatesMap.get(tempId))) {
                    num = NumberUtil.mul(storeCartVO.getCartNum(),
                            storeCartVO.getProductInfo().getAttrInfo().getVolume()).doubleValue();
                }

                ShippingTemplatesRegionDO shippingTemplatesRegion = shippingTemplatesRegionMap.get(tempId);
                BigDecimal price = NumberUtil.round(NumberUtil.mul(storeCartVO.getCartNum(),
                        storeCartVO.getTruePrice()), 2);
                if (!templateDTOMap.containsKey(tempId)) {
                    TemplateDto templateDTO = TemplateDto.builder()
                            .number(num)
                            .price(price)
                            .first(shippingTemplatesRegion.getFirst().doubleValue())
                            .firstPrice(shippingTemplatesRegion.getFirstPrice())
                            ._continue(shippingTemplatesRegion.getContinues().doubleValue())
                            .continuePrice(shippingTemplatesRegion.getContinuePrice())
                            .tempId(tempId)
                            .cityId(cityId)
                            .build();
                    templateDTOMap.put(tempId, templateDTO);
                } else {
                    TemplateDto templateDTO = templateDTOMap.get(tempId);
                    templateDTO.setNumber(templateDTO.getNumber() + num);
                    templateDTO.setPrice(NumberUtil.add(templateDTO.getPrice().doubleValue(), price));
                }


            }

            //处理包邮情况
            jj: for (Map.Entry<Integer, TemplateDto> entry : templateDTOMap.entrySet()) {
                Integer mapKey = entry.getKey();
                TemplateDto mapValue = entry.getValue();

                Long count = shippingTemplatesFreeService.count(Wrappers.<ShippingTemplatesFreeDO>lambdaQuery()
                        .eq(ShippingTemplatesFreeDO::getTempId, mapValue.getTempId())
                        .eq(ShippingTemplatesFreeDO::getCityId, mapValue.getCityId())
                        .le(ShippingTemplatesFreeDO::getNumber, mapValue.getNumber())
                        .le(ShippingTemplatesFreeDO::getPrice, mapValue.getPrice()));
                //满足包邮条件剔除
                if (count > 0) {
                    templateDTOMap.remove(mapKey);
                    break jj;
                }
            }

            //处理区域邮费
            boolean isFirst = true; //用来是否多个产品的标识 false表示数量大于1
            for (TemplateDto templateDTO : templateDTOMap.values()) {
                if (isFirst) {//首件
                    //只满足首件
                    if (Double.compare(templateDTO.getNumber(), templateDTO.getFirst()) <= 0) {
                        storePostage = NumberUtil.round(NumberUtil.add(storePostage,
                                templateDTO.getFirstPrice()), 2);
                    } else {
                        BigDecimal firstPrice = NumberUtil.add(storePostage, templateDTO.getFirstPrice());

                        if (templateDTO.get_continue() <= 0) {
                            storePostage = firstPrice;
                        } else {
                            //续件平均值且向上取整数
                            double average = Math.ceil(NumberUtil.div(NumberUtil.sub(templateDTO.getNumber(),
                                    templateDTO.getFirst()),
                                    templateDTO.get_continue().doubleValue()));
                            //最终邮费
                            storePostage = NumberUtil.add(firstPrice, NumberUtil.mul(average,
                                    templateDTO.getContinuePrice()));
                        }

                    }

                    isFirst = false;
                } else {
                    //多件直接在以前的基数继续续建
                    if (templateDTO.get_continue() > 0) {
                        //续件平均值且向上取整数
                        double average = Math.ceil(
                                NumberUtil.div(
                                        templateDTO.getNumber(),
                                        templateDTO.get_continue()
                                )
                        );
                        //最终邮费
                        storePostage = NumberUtil.add(storePostage.doubleValue(), NumberUtil.mul(average,
                                templateDTO.getContinuePrice()));
                    }
                }
            }
        }


        return storePostage;
    }



}
