package com.iformall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.OrderSaveDto;
import com.iformall.domain.dto.WxSharingOrderDto;
import com.iformall.domain.po.*;
import com.iformall.domain.po.msg.FmInsideOrderSuccessMsg;
import com.iformall.domain.vo.*;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.mq.MqBaseProducer;
import com.iformall.service.*;
import com.iformall.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WxOrderServiceImpl implements WxOrderService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    RedisLock redisLock;

    @Autowired
    WxAppinfoMapper wxAppinfoMapper;

    @Autowired
    WxPayAccountMapper wxPayAccountMapper;

    @Autowired
    WxMallMapper wxMallMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxCUserMapper wxCUserMapper;

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxOrderMapper wxOrderMapper;

    @Autowired
    WxCouponOrderMapper wxCouponOrderMapper;

    @Autowired
    WxCUserService wxCUserService;

    @Autowired
    WxPayOrderMapper wxPayOrderMapper;

    @Autowired
    WxMerchantBUserMapper wxMerchantBUserMapper;

    @Autowired
    WxAppinfoService wxAppinfoService;

    @Autowired
    WxPayOrderService wxPayOrderService;

    @Autowired
    WxScoreRulesService wxScoreRulesService;

    @Autowired
    WxCUserTagsService wxCUserTagsService;

    @Autowired
    WxCouponActionLogService wxCouponActionLogService;

    @Autowired
    WxProfitSharingOrderService wxProfitSharingOrderService;

    @Autowired
    WxCouponMerchantMapper wxCouponMerchantMapper;

    @Autowired
    WxCardInfoMapper wxCardInfoMapper;

    @Autowired
    WxCouponSendService wxCouponSendService;

    @Autowired
    WxOrderPressMapper wxOrderPressMapper;

    @Autowired
    WxOrderGroupMapper wxOrderGroupMapper;

    @Autowired
    WxCreditHistoryService wxCreditHistoryService;

    @Autowired
    WxCouponChannelMapper wxCouponChannelMapper;

    @Autowired
    private MqBaseProducer mqBaseProducer;

    @Autowired
    private WxCUserBasicInfoMapper wxCUserBasicInfoMapper;

    @Autowired
    private WxMsgLimitService wxMsgLimitService;

    @Autowired
    private WxCouponPasswordMapper couponPasswordMapper;

    @Autowired
    ExcelService excelService;

    @Override
    public PageInfo<WxOrder> listAsPage(WxOrder record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findList(record));
    }

    @Override
    public ResultData microPayListOnDateAsPage(Long bUserId, Integer type, String date, Integer pageIndex, Integer pageSize) {
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(bUserId.longValue());
        if (wxMerchantBUser == null) {
            logger.error("B端用户不存在:" + bUserId);
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }

        WxMerchant wxMerchant = wxMerchantMapper.selectById(wxMerchantBUser.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在:" + bUserId);
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }

        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
        String dateString;
        Date startDate;
        Date endDate;

        if (date == null) {
            endDate = new Date();
            dateString = fmt.format(new Date());
            try {
                startDate = fmt.parse(dateString);
            } catch (ParseException e) {
                return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR);
            }
        } else {
            try {
                startDate = fmt.parse(date);
            } catch (ParseException e) {
                return new ResultData(ErrorCode.SYS_PARAMETER_CAST_ERROR);
            }
            Calendar cal = Calendar.getInstance();
            cal.setTime(startDate);
            cal.add(Calendar.DATE, 1);
            endDate = cal.getTime();
        }

        Map dateMap = new HashMap();
        dateMap.put("startDate", startDate);
        dateMap.put("endDate", endDate);
        dateMap.put("merchantId", wxMerchant.getId());
        dateMap.put("type", type);

        Map resultMap = new HashMap();

        if (pageIndex == null || pageSize == null) {
            List<WxOrderPayVo> list;
            list = wxOrderMapper.findListOfMicroPayOrderByDate(dateMap);
            logger.info("find " + list.size() + " order from " + startDate + " to " + new Date());
            int total_price = 0;
            for (WxOrder order : list) {
                total_price = total_price + order.getPayment();
            }
            resultMap.put("amount", total_price);
        } else {
            resultMap.put("list", PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findListOfMicroPayOrderByDate(dateMap)));
        }
        return new ResultData(resultMap);
    }

    /**
     * 拼团数量
     *
     * @param user
     * @param counpon
     * @return
     */
    private int getUserOrderGroupCount(WxCUser user, WxCoupon counpon) {
        // + Order 待支付
        try {
            WxOrder orderQ = new WxOrder();
            orderQ.setTenantId(user.getTenantId());
            orderQ.setProductId(counpon.getId());
            orderQ.setType(EnumOrderType.COUPON.getCode());
            orderQ.setCUserId(user.getId());
            orderQ.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode());
            return wxOrderMapper.countList(orderQ);
        } catch (Exception e) {
            logger.error("购买是否超限-DB, couponId: " + counpon.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_FAIL);
        }

    }


    /**
     * 用户购买的订单数量
     *
     * @param user
     * @param counpon
     * @return
     */
    private int getUserOrderCount(WxCUser user, WxCoupon counpon) {
        // + Order 待支付
        try {
            WxOrder orderQ = new WxOrder();
            orderQ.setTenantId(user.getTenantId());
            orderQ.setProductId(counpon.getId());
            orderQ.setType(EnumOrderType.COUPON.getCode());
            orderQ.setCUserId(user.getId());
            List<Integer> statusS = new ArrayList<>();
            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode());
            orderQ.setStatusS(statusS);
            return wxOrderMapper.countList(orderQ);
        } catch (Exception e) {
            logger.error("购买是否超限-DB, couponId: " + counpon.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_FAIL);
        }

    }

    /**
     * 用户购买的订单数量
     *
     * @param user
     * @param counpon
     * @return
     */
    public WxOrder getUnPaidOrder(WxCUser user, WxCoupon counpon) {
        // + Order 待支付
        try {
            WxOrder orderQ = new WxOrder();
            orderQ.setTenantId(user.getTenantId());
            orderQ.setProductId(counpon.getId());
            orderQ.setType(EnumOrderType.COUPON.getCode());
            orderQ.setCUserId(user.getId());
            List<Integer> statusS = new ArrayList<>();
            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode());
            orderQ.setStatusS(statusS);
            List<WxOrder> orders = wxOrderMapper.findList(orderQ);
            if (orders.size() >= 1) {
                return orders.get(0);
            }
        } catch (Exception e) {
            logger.error("待支付Order, couponId: " + counpon.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND);
        }
        return null;
    }

    /**
     * 用户正在参加的新手活动
     *
     * @param user
     * @return
     */
    public int countCouponConditionType1(WxCUser user) {
        // + Order 待支付
        try {
            WxOrder orderQ = new WxOrder();
            orderQ.setTenantId(user.getTenantId());
            orderQ.setType(EnumOrderType.COUPON.getCode());
            orderQ.setCUserId(user.getId());
            List<Integer> statusS = new ArrayList<>();
            statusS.add(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS.getCode());

            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_PRESS_COMPLETE.getCode());

            statusS.add(EnumOrderStatus.ORDER_STATUS_COOPERATING.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode());
            statusS.add(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode());
            orderQ.setStatusS(statusS);
            return wxOrderMapper.countCouponConditionType1(orderQ);
        } catch (Exception e) {
            logger.error("用户正在参加的新手活动, userId: " + user.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_NOT_FIND);
        }
    }

    /**
     * 用户购买的券包数量- 待使用的券
     *
     * @param user
     * @param counpon
     * @return
     */
    private int getUserCouponOrderCount(WxCUser user, WxCoupon counpon) {
        // + couponOrder ---待使用
        try {
            WxCouponOrder couponOrderQ = new WxCouponOrder();
            couponOrderQ.setTenantId(user.getTenantId());
            couponOrderQ.setCouponId(counpon.getId());
            couponOrderQ.setCUserId(user.getId());
            if (counpon.getSendType().equals(EnumCouponSendType.PASSIVE)) {
                couponOrderQ.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USE_WAIT.getCode());
            }
            return wxCouponOrderMapper.findCount(couponOrderQ);
        } catch (Exception e) {
            logger.error("购买是否超限-DB, couponId: " + counpon.getId() + ", e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_FAIL);
        }

    }

    /**
     * 商户注券减库存
     *
     * @param user
     * @param coupon
     * @param couponIdStr
     * @param wxCouponSendVo
     */
    private void stockMerchantReduce(WxCUser user, WxCoupon coupon, String couponIdStr, WxCouponSendVo wxCouponSendVo) {
        long time = System.currentTimeMillis() + RedisLock.TIMEOUT;
        String timeStr = String.valueOf(time);
        // 库存加锁
        if (!redisLock.lock(couponIdStr, timeStr)) {
            logger.error("此券被锁定, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.TOO_MANY_REQUEST.getCode(), coupon.getTitle() + ErrorCode.TOO_MANY_REQUEST.getMessage());
        }

        JSONObject jo = JSONObject.parseObject(wxCouponSendVo.getConditions());
        int merchantSend = jo.getIntValue(WxCouponSend.KEY_MERCHANT_SEND);
        int merchantRemain = jo.getIntValue(WxCouponSend.KEY_MERCHANT_REMAIN);

        // 检查 优惠券 库存
        if (merchantRemain <= 0) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            logger.error("此券库存为0, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY.getCode(), coupon.getTitle() + ErrorCode.REMAIN_IS_EMPTY.getMessage());
        }

        int count = 0;
        // 有价券 TODO 当前只支持系统券(免费券)
//        if (coupon.getSalePrice() > 0) {
//            // 检查是否未支付订单
//            try {
//                count = getUserOrderCount(user, coupon);
//            } catch (Exception e) {
//                //解锁
//                redisLock.unlock(couponIdStr, timeStr);
//                throw new MallinkException(ErrorCode.DB_FAIL);
//            }
//            if (count > 0) {
//                //解锁
//                redisLock.unlock(couponIdStr, timeStr);
//                logger.error("此券有未支付的订单, couponId: " + couponIdStr + ", count: " + count);
//                throw new MallinkException(ErrorCode.ORDER_UNPAID);
//            }
//        }
        // 检查用户已购买数量
        try {
            count = getUserCouponOrderCount(user, coupon);
        } catch (Exception e) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        if (count >= coupon.getUseLimitQuantity()) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count);
            throw new MallinkException(ErrorCode.ORDER_IS_LIMITED.getCode(), coupon.getTitle() + ErrorCode.ORDER_IS_LIMITED.getMessage());
        }

        try {
            // 减库存
            wxCouponSendService.reduceMerchantSend(wxCouponSendVo.getId(), merchantRemain, merchantSend, 1);
        } catch (RuntimeException e) {
            logger.error("此券减库存失败, couponId: {}, error: {}", couponIdStr, e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_IS_FAIL.getCode(), coupon.getTitle() + ErrorCode.ORDER_IS_LIMITED.getMessage());
        } finally {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
        }
    }


    /**
     * 减库存
     *
     * @param user
     * @param coupon
     * @param couponIdStr
     */
    private void stockReduce(WxCUser user, WxCoupon coupon, String couponIdStr) {
        long time = System.currentTimeMillis() + RedisLock.TIMEOUT;
        String timeStr = String.valueOf(time);
        // 库存加锁
        if (!redisLock.lock(couponIdStr, timeStr)) {
            logger.error("此券被锁定, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.TOO_MANY_REQUEST);
        }

        // 检查 优惠券 库存
        if (coupon.getRemainInventory() <= 0) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            logger.error("此券库存为0, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY);
        }

        int count = 0;
        // 有价券
        if (coupon.getSalePrice() > 0) {
            // 检查是否未支付订单
            try {
                count = getUserOrderCount(user, coupon);
            } catch (Exception e) {
                //解锁
                redisLock.unlock(couponIdStr, timeStr);
                throw new MallinkException(ErrorCode.DB_FAIL);
            }
            if (count > 0) {
                //解锁
                redisLock.unlock(couponIdStr, timeStr);
                logger.error("此券有未支付的订单, couponId: " + couponIdStr + ", count: " + count);
                throw new MallinkException(ErrorCode.ORDER_UNPAID);
            }
        }
        //检查拼团中的数量
        try {
            count = getUserOrderGroupCount(user, coupon);
        } catch (Exception e) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        if (count >= coupon.getUseLimitQuantity()) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count);
            throw new MallinkException(ErrorCode.ORDER_IS_LIMITED);
        }

        // 检查用户已购买数量
        try {
            count = getUserCouponOrderCount(user, coupon);
        } catch (Exception e) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            throw new MallinkException(ErrorCode.DB_FAIL);
        }
        if (count >= coupon.getUseLimitQuantity()) {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
            logger.error("此券购买数量已超限, couponId: " + couponIdStr + ", count: " + count);
            throw new MallinkException(ErrorCode.ORDER_IS_LIMITED);
        }

        try {
            // 减库存
            wxCouponMapper.reduceInventory(coupon.getId(), 1, coupon.getRemainInventory());
        } catch (RuntimeException e) {
            logger.error("此券减库存失败, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.ORDER_IS_FAIL);
        } finally {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
        }
    }

    @Override
    public void stockBack(WxOrder updateOrder) {
        // 已取消/已退款，库存加1
        // 获取订单相关coupon
        Long couponId = updateOrder.getProductId();
        String couponIdStr = "" + couponId;
        //加锁
        long time = System.currentTimeMillis() + RedisLock.TIMEOUT;
        String timeStr = String.valueOf(time);

        if (!redisLock.lock(couponIdStr, timeStr)) {
            logger.error("此券被锁定, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.TOO_MANY_REQUEST);
        }
        WxCoupon coupon = null;
        try {
            coupon = wxCouponMapper.selectById(couponId);
        } catch (Exception e) {
            logger.error("券未找到, e:" + e.getMessage());
            redisLock.unlock(couponIdStr, timeStr);
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        if (coupon == null) {
            logger.error("券未找到, " + couponIdStr);
            redisLock.unlock(couponIdStr, timeStr);
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }

        try {
            wxCouponMapper.backInventory(coupon.getId(), 1, coupon.getRemainInventory());
        } catch (Exception e) {
            logger.error("数据库更新失败，库存+1失败, e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "库存恢复失败");
        } finally {
            //解锁
            redisLock.unlock(couponIdStr, timeStr);
        }
    }

    /**
     * 检查券商户是否可用
     *
     * @param couponId
     * @return
     */
    private boolean isCouponMerchantValid(Long couponId) {
        Map paramMap = new HashMap<>();
        paramMap.put("productId", couponId);
        List<WxMerchantVo> merchantVoList = wxCouponMerchantMapper.findMerchantNameList(paramMap);
        if (merchantVoList.stream().anyMatch((cm -> cm.getMerchantStatus().equals(EnumMerchantStatus.VALID.getCode())))) {
            return true;
        }
        return false;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxOrder saveMicroPayOrder(WxMerchantBUser user, String totalFeeStr) {
        // 检查用户
        if (user == null) {
            logger.error("用户不存在");
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        // 检查商户
        WxMerchant wxMerchant = wxMerchantMapper.selectById(user.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在, merchantId: " + user.getMerchantId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        if (wxMerchant.getStatus() == EnumMerchantStatus.NOT_VALID.getCode()) {
            logger.error("商户已禁用, merchantId: " + user.getMerchantId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_VALID);
        }

        WxOrder record = new WxOrder();

        Date curr = new Date();

        BigDecimal totalFee = new BigDecimal(totalFeeStr);
        totalFee.setScale(2, BigDecimal.ROUND_HALF_UP); // 第一个变量是小数位数，第二个变量是取舍方法(四舍五入)

        int payment = totalFee.multiply(new BigDecimal(100)).intValue();

        final IdWorker idWorker = IdWorker.get();
        Long orderNumber = idWorker.nextId();

        // body
        // tenant_id + merchant_id + title + subtitle
        String bodyStr = "刷卡支付, 金额:" + totalFeeStr;

        record.setId(orderNumber);
        record.setTenantId(user.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setType(EnumOrderType.MICROPAY.getCode());
        record.setProductId(user.getId());
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setPayment(payment);
        record.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
        record.setDetail(bodyStr);
        record.setCreateDate(curr);
        record.setUpdateDate(curr);

        try {
            // 保存订单
            wxOrderMapper.insert(record);
        } catch (RuntimeException e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }
        return record;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxOrder saveMicroPayOrderV2(WxMerchantBUser user, WxCUser cUser, Integer payment) {
        // 检查用户
        if (user == null) {
            logger.error("用户不存在");
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        // 检查商户
        WxMerchant wxMerchant = wxMerchantMapper.selectById(user.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在, merchantId: " + user.getMerchantId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        if (wxMerchant.getStatus() == EnumMerchantStatus.NOT_VALID.getCode()) {
            logger.error("商户已禁用, merchantId: " + user.getMerchantId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_VALID);
        }

        WxOrder record = new WxOrder();

        Date curr = new Date();

        final IdWorker idWorker = IdWorker.get();
        Long orderNumber = idWorker.nextId();

        // body
        // tenant_id + merchant_id + title + subtitle
        String bodyStr = "刷卡支付, 金额:" + payment;

        record.setId(orderNumber);
        record.setTenantId(user.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setType(EnumOrderType.MICROPAY.getCode());
        record.setProductId(user.getId());
        if (cUser != null) {
            record.setCUserId(cUser.getId());
        }
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setPayment(payment);
        record.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
        record.setDetail(bodyStr);
        record.setCreateDate(curr);
        record.setUpdateDate(curr);

        try {
            // 保存订单
            wxOrderMapper.insert(record);
        } catch (RuntimeException e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }
        return record;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxOrder saveCardPayOrder(WxMerchant merchant, Long cUserId, String totalFeeStr, Integer payment) {
        Date curr = new Date();

        final IdWorker idWorker = IdWorker.get();
        Long orderNumber = idWorker.nextId();

        // body
        // tenant_id + merchant_id + title + subtitle
        String bodyStr = "C扫B储值卡支付, 金额:" + totalFeeStr;

        WxOrder record = new WxOrder();
        record.setId(orderNumber);
        record.setTenantId(merchant.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setType(EnumOrderType.PREPAIDCARD.getCode());
        record.setProductId(merchant.getId());
        record.setCUserId(cUserId);
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setPayment(payment);
        record.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode());
        record.setDetail(bodyStr);
        record.setCreateDate(curr);
        record.setUpdateDate(curr);

        try {
            // 保存订单
            wxOrderMapper.insert(record);
        } catch (RuntimeException e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }
        return record;
    }

    /**
     * 创建 couponOrder
     *
     * @param user
     * @param order
     * @param coupon
     */
    private WxCouponOrder createCouponOrder(WxOrder order, WxCUser user, WxCoupon coupon, Long couponPasswordId) {
        Date curr = new Date();
        Date valid_date = null;
        int limit_days = Constant.WX_LIMIT_DAYS;
        if (coupon.getValidType().equals(EnumValidStatus.VALID_RANGE.getCode()) ||
                coupon.getType().equals(EnumCouponType.COUPON_TINGCHE.getCode())) {
            valid_date = coupon.getValidEndDate();
            if (coupon.getSalePrice() > 0 && !coupon.checkIsCard()) {
                // 有价券核销有效期不能大于分账过期时间
                Date limit_date = DateUtils.getTimeAfterDays(limit_days, curr);
                if (valid_date.after(limit_date)) {
                    valid_date = limit_date;
                }
            }
        } else {
            if (coupon.getSalePrice() > 0 && !coupon.checkIsCard()) {
                // 有价券核销有效期不能大于分账过期时间
                if (coupon.getValidDays() < Constant.WX_LIMIT_DAYS) {
                    limit_days = coupon.getValidDays();
                }
            } else {
                limit_days = coupon.getValidDays();
            }
            valid_date = DateUtils.getTimeAfterDays(limit_days, curr);
        }
        boolean isCard = false;
        // 检查是否是储值卡
        if (coupon.getType().equals(EnumCouponType.CARD_MULTIMCH.getCode())) {
            isCard = true;
        }
        final IdWorker idWorker = IdWorker.get();

        WxCouponOrder couponOrder = new WxCouponOrder();
        couponOrder.setId(idWorker.nextId());
        couponOrder.setTenantId(user.getTenantId());
        couponOrder.setCouponId(order.getProductId());
        couponOrder.setCouponType(coupon.getType());
        couponOrder.setCUserId(user.getId());
        couponOrder.setOwnerId(user.getId());
        couponOrder.setAutoRefund(coupon.getAutoRefund());
        couponOrder.setOrderId(order.getOrderNumber());
        couponOrder.setExpiredTime(valid_date);
        if (!isCard) {
            couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USE_WAIT.getCode());
        } else {
            couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.CARD_USING.getCode());
        }
        couponOrder.setCreateDate(curr);
        couponOrder.setUpdateDate(curr);
        couponOrder.setCouponPrice(order.getPayment());

        wxCouponOrderMapper.insert(couponOrder);

        /// 储值卡信息添加
        if (isCard) {
            WxPayOrder payOrder = null;
            Integer fee = 0;
            WxCardInfo cardInfo = new WxCardInfo();
            cardInfo.setId(couponOrder.getId());
            cardInfo.setTenantId(user.getTenantId());
            cardInfo.setCouponId(order.getProductId());
            cardInfo.setAmount(coupon.getPrice());
            cardInfo.setSaleAmount(coupon.getSalePrice());
            cardInfo.setRemainingAmount(coupon.getPrice());

            if (!coupon.checkIsFree()) {
                // 有价卡
                try {
                    WxPayOrder payOrderQ = new WxPayOrder();
                    payOrderQ.setTenantId(user.getTenantId());
                    payOrderQ.setOrderId(order.getId());
                    payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());
                    payOrder = wxPayOrderMapper.selectOne(new QueryWrapper(payOrderQ));
                } catch (Exception e) {
                    logger.error("payOrder not found:" + e.getMessage());
                }
                cardInfo.setTransactionId(payOrder.getTransactionId());
                if (payOrder.getShareAmount() != null) {
                    // 开启分账
                    fee = payOrder.getPayAmount() - payOrder.getShareAmount();
                    cardInfo.setShareFeeAmount(payOrder.getShareAmount());
                    cardInfo.setRemainingShareFeeAmount(payOrder.getShareAmount());
                    cardInfo.setRateAmount(payOrder.getRateAmount());
                } else {
                    // 未开启分账
                    WxPayAccount payAccount = null;
                    WxPayAccount payAccountQ = new WxPayAccount();
                    payAccountQ.setTenantId(cardInfo.getTenantId());
                    try {
                        payAccount = wxPayAccountMapper.selectOne(new QueryWrapper<>(payAccountQ));
                        fee = PayUtils.getPayRate(payOrder.getPayAmount(), payAccount.getRate(), false);
                        Integer shareAmount = payOrder.getPayAmount() - fee;
                        cardInfo.setShareFeeAmount(shareAmount);
                        cardInfo.setRemainingShareFeeAmount(shareAmount);
                        if (payAccount.getRealRate() != null) {
                            int iRealChargeFee = PayUtils.getPayRate(payOrder.getPayAmount(), payAccount.getRealRate(), true);
                            if (fee > iRealChargeFee) {
                                cardInfo.setRateAmount(fee - iRealChargeFee);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("获取payAccount error: " + cardInfo.getTenantId());
                    }
                }
            } else {
                // 免费卡
                cardInfo.setShareFeeAmount(0);
                cardInfo.setRemainingShareFeeAmount(0);
                cardInfo.setRateAmount(0);
                if (coupon.getPasswordSupport().equals(EnumCouponPasswordSupport.SUPPORTED.getCode())) {
                    WxCouponPassword updateCPwd = new WxCouponPassword();
                    updateCPwd.setId(couponPasswordId);
                    updateCPwd.setCardId(cardInfo.getId());
                    updateCPwd.setStatus(EnumCouponPasswordStatus.USED.getCode());
                    couponPasswordMapper.updateById(updateCPwd);
                }
            }

            cardInfo.setServiceFeeAmount(fee);
            cardInfo.setCreateDate(curr);
            cardInfo.setUpdateDate(curr);
            cardInfo.setSupportTransfer(coupon.getSupportTransfer());

            //检查卡是否下架，如果是，不可转赠
            WxCouponChannel wxCouponChannel = wxCouponChannelMapper.selectById(order.getCouponChannelId());
            if (wxCouponChannel != null && wxCouponChannel.getStatus().equals(EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode())) {
                cardInfo.setSupportTransfer(EnumCouponTransfer.NO.getCode());
            }
            wxCardInfoMapper.insert(cardInfo);
        }
        return couponOrder;
    }

    @Override
    @Transactional(propagation = Propagation.NESTED, readOnly = false, rollbackFor = {Exception.class})
    public WxCouponOrder sendFreeCouponToUser(Long userId, Long couponId, WxCouponSendVo wxCouponSendVo) {
        // check 用户状态
        WxCUser user = null;
        try {
            user = wxCUserMapper.selectById(userId);
        } catch (Exception e) {
            logger.error("userId : " + userId + ", e: " + e.getMessage());
        }
        if (user == null) {
            logger.error("用户不存在, userId: " + userId);
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        // 检查券状态
        String couponIdStr = String.valueOf(couponId);
        WxCoupon coupon = wxCouponMapper.selectById(couponId);
        if (coupon == null) {
            logger.error("券不存在, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        if (coupon.getStatus() == EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode()) {
            logger.error("券已下架, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.COUPON_IS_TAKE_OFF.getCode(), coupon.getTitle() + ErrorCode.COUPON_IS_TAKE_OFF.getMessage());
        }
        if (coupon.getSalePrice() != 0) {
            logger.error("券不免费, couponId: " + couponIdStr);
            throw new MallinkException(ErrorCode.COUPON_IS_NOT_FREE.getCode(), coupon.getTitle() + ErrorCode.COUPON_IS_NOT_FREE.getMessage());
        }

        if (Objects.nonNull(wxCouponSendVo) && Objects.equals(EnumCouponSendSendType.MERCHANT.getCode(), wxCouponSendVo.getSendType())) {
            // 商户注券减库存操作
            stockMerchantReduce(user, coupon, couponIdStr, wxCouponSendVo);
        } else {
            // 减库存操作
            stockReduce(user, coupon, couponIdStr);
        }

        int payment = coupon.getSalePrice();

        Date curr = new Date();

        final IdWorker idWorker = IdWorker.get();
        Long orderNumber = idWorker.nextId();

        // body
        // tenant_id + merchant_id + title + subtitle
        String bodyStr = coupon.getTitle() + "/" + coupon.getSubTitle();

        WxOrder record = new WxOrder();
        record.setId(orderNumber);
        record.setTenantId(user.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setProductId(couponId);
        record.setType(EnumOrderType.COUPON.getCode());
        record.setCUserId(user.getId());
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setPayment(payment);
        record.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS.getCode());
        record.setDetail(bodyStr);
        record.setCreateDate(curr);
        record.setUpdateDate(curr);

        // 保存订单
        try {
            wxOrderMapper.insert(record);
        } catch (Exception e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR.getCode(), coupon.getTitle() + ErrorCode.ORDER_SAVE_ERR.getMessage());
        }

        //  创建couponOrder
        WxCouponOrder couponOrder = null;
        try {
            couponOrder = createCouponOrder(record, user, coupon, null);
        } catch (Exception e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.COUPON_ORDER_SAVE_ERR.getCode(), coupon.getTitle() + ErrorCode.COUPON_ORDER_SAVE_ERR.getMessage());
        }

        return couponOrder;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public int couponOrderSuccess(WxOrder updateOrder) {
        Date currentDate = new Date();
        // 检查券相关
        WxCoupon coupon = wxCouponMapper.selectById(updateOrder.getProductId());
        if (coupon == null) {
            logger.error("券不存在, couponId: " + updateOrder.getProductId());
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        // 检查用户
        WxCUser user = wxCUserMapper.selectById(updateOrder.getCUserId());
        if (user == null) {
            logger.error("用户不存在, userId: " + updateOrder.getCUserId());
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }
        // 已支付,更新支付时间
        WxOrder updateT = new WxOrder();
        updateT.setId(updateOrder.getId());
        updateT.setPaymentTime(currentDate);
        //拼团到此处为已完成状态
        if (updateOrder.getOrderGroupId().equals(0L)) {
            updateT.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS.getCode());
        } else {
            // 拼团设为已完成状态
            updateT.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode());
        }
        updateT.setUpdateDate(currentDate);
        int ret = 0;
        try {
            ret = wxOrderMapper.updateById(updateT);
        } catch (Exception e) {
            logger.error("订单更新失败：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_UPDATE_ERR);
        }

        //  创建couponOrder
        try {
            createCouponOrder(updateOrder, user, coupon, null);
        } catch (Exception e) {
            logger.error("创建券包：" + e.getMessage());
            throw new MallinkException(ErrorCode.COUPON_ORDER_SAVE_ERR);
        }


        return ret;
    }

    private void sendInsideOrderSuccessMsg(WxOrder updateOrder, WxCoupon coupon, WxCUser user) {
        FmInsideOrderSuccessMsg orderSuccess = new FmInsideOrderSuccessMsg();
        orderSuccess.setMsgType(EnumMsgRecordType.INSIDE_ORDER_SUCCESS.getCode());
        orderSuccess.setTenantId(updateOrder.getTenantId());
        orderSuccess.setOrderId(updateOrder.getId());
        orderSuccess.setCUserId(user.getId());
        orderSuccess.setCouponId(coupon.getId());
        mqBaseProducer.sendMessage(orderSuccess, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
    }

    @Override
    public void sendOrderSuccessActionMsg(WxOrder updateOrder) {
        // 检查券相关
        WxCoupon coupon = wxCouponMapper.selectById(updateOrder.getProductId());
        if (coupon == null) {
            logger.error("券不存在, couponId: " + updateOrder.getProductId());
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        if (coupon.getStatus() == EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode()) {
            logger.error("券已下架, couponId: " + updateOrder.getProductId());
            throw new MallinkException(ErrorCode.COUPON_IS_TAKE_OFF);
        }
        // 检查用户
        WxCUser user = wxCUserMapper.selectById(updateOrder.getCUserId());
        if (user == null) {
            logger.error("用户不存在, userId: " + updateOrder.getCUserId());
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }

        // 记录活动
        JSONObject jo = null;
        try {
            jo = JSONObject.parseObject(coupon.getConditions());
        } catch (Exception e) {
            logger.error("购买券条件判断错误:ID=" + coupon.getId() + e.getMessage());
        }
        if (jo != null) {
            if (jo.getIntValue("type") == EnumCouponConditionType.NEW_MEMBER.getCode()) {
                wxCUserBasicInfoMapper.incActRecordById(user.getId());
            }
        }

        sendInsideOrderSuccessMsg(updateOrder, coupon, user);
    }

    /**
     * 下订单后操作
     *
     * @param updateOrder
     * @param coupon
     * @param user
     */
    public void actionAfterCouponOrderSuccess(WxOrder updateOrder, WxCoupon coupon, WxCUser user) {
        /// TODO 晚上会定时打一下tag
        wxCUserTagsService.triggerAssignTags(EnumAssignTagsTrigger.ASSIGN_TAGS_TRIGGER_BUY, user);

        //  交易发券
        try {
            wxCouponSendService.sendCouponToUser(EnumCouponSendSendType.C_ORDER, updateOrder);
        } catch (Exception e) {
            logger.error("订单发券：" + e.getMessage());
        }

    }

    @Override
    public Map<String, Long> summary(WxOrderQueryVo wxOrderQueryVo) {
        List<WxOrder> listOrder = wxOrderMapper.findListOrder(wxOrderQueryVo);
        Long payment = listOrder.stream().collect(Collectors.summingLong(WxOrder::getPayment));
        Long pay = listOrder.stream().collect(Collectors.summingLong(WxOrder::getPay));
        Map<String, Long> data = new HashMap<>();
        data.put("payment", payment);
        data.put("pay", pay);
        return data;
    }

    @Override
    public void exportData(WxOrderQueryVo wxOrderQueryVo, HttpServletRequest request, HttpServletResponse response) {
        List<WxOrder> list = wxOrderMapper.findListOrder(wxOrderQueryVo);
        Map<String, Long> summary = summary(wxOrderQueryVo);
        Long payment = summary.get("payment");
        Long pay = summary.get("pay");
        String paymentStr = new BigDecimal(payment).divide(new BigDecimal(100)).toPlainString();
        String payStr = new BigDecimal(pay).divide(new BigDecimal(100)).toPlainString();
        WxOrder order = new WxOrder();
        order.setPayStr(payStr);
        order.setPaymentStr(paymentStr);
        order.setOrderStatus(-1);
        order.setAttribute(-1);
        list.add(order);
        excelService.exportExcel(list, null, "线上交易", WxOrder.class, "线上交易.xlsx", response, false);
    }

    /**
     * 积分设置来源商户
     */
    private void setMerchantId(WxCoupon coupon, WxCreditHistory creditHistory) {
        WxCouponMerchant wxCouponMerchant = new WxCouponMerchant();
        wxCouponMerchant.setProductId(coupon.getId());
        wxCouponMerchant.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
        List<WxCouponMerchant> list = wxCouponMerchantMapper.findList(wxCouponMerchant);
        if (list != null && list.size() > 0) {
            if (list.size() == 1) {
                creditHistory.setMerchantId(list.get(0).getMerchantId());
            }
            if (list.size() > 1) {
                creditHistory.setMerchantId(Long.valueOf(EnumMerchantType.MERCHANT_MORE.getCode()));
            }
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public int microPayOrderSuccess(WxOrder updateOrder) {
        Date currentDate = new Date();
        // C端用户
        WxCUser user = wxCUserMapper.selectById(updateOrder.getCUserId());
        if (user == null) {
            logger.error("用户不存在, userId: " + updateOrder.getCUserId());
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }
        // B端用户
        WxMerchantBUser bUser = wxMerchantBUserMapper.selectById(updateOrder.getProductId());
        if (bUser == null) {
            logger.error("B端用户不存在, bUserId: " + updateOrder.getProductId());
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }
        // 基于B端User查找merchant
        WxMerchant wxMerchant = wxMerchantMapper.selectById(bUser.getMerchantId());
        if (wxMerchant == null) {
            logger.error("商户不存在, merchantId: " + bUser.getMerchantId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        // 已支付,更新支付时间
        updateOrder.setPaymentTime(currentDate);
        updateOrder.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS.getCode());
        updateOrder.setUpdateDate(currentDate);
        int ret = 0;
        try {
            ret = wxOrderMapper.updateById(updateOrder);
        } catch (Exception e) {
            logger.error("订单更新失败：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_UPDATE_ERR);
        }

        // 成长值 计算
        try {
            wxScoreRulesService.addScore2(EnumScoreType.CONSUMPTION, updateOrder, wxMerchant.getBusinessId());
        } catch (Exception e) {
            logger.error("成长值:" + e.getMessage());
        }
        // 积分 计算
        try {
            //扣减积分操作记录
            WxCreditHistory creditHistory = new WxCreditHistory();
            creditHistory.setOperatorType(EnumUserType.CUSER.getCode());
            creditHistory.setOperatorId(user.getId());
            creditHistory.setCUserId(user.getId());
            creditHistory.setCreateDate(new Date());
            creditHistory.setTenantId(user.getTenantId());
            creditHistory.setCreditType(EnumScoreType.CONSUMPTION.getCode());
            if (updateOrder.getCouponChannelId() != null) {
                WxCouponChannel wxCouponChannel = wxCouponChannelMapper.selectById(updateOrder.getCouponChannelId());
                creditHistory.setCouponId(wxCouponChannel.getCouponId());
            }
            creditHistory.setBusinessId(wxMerchant.getBusinessId());
            creditHistory.setSpend(updateOrder.getPayment());
            creditHistory.setMerchantId(wxMerchant.getId());
            wxCreditHistoryService.saveOrUpdate(creditHistory);
        } catch (Exception e) {
            logger.error("积分值:" + e.getMessage());
        }

        return ret;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public int updateOrderStatus(WxOrder updateOrder, EnumOrderStatus enumOrderStatus) {
        Date currentDate = new Date();
        switch (enumOrderStatus) {
            case ORDER_STATUS_OVERTIME_CANCEL:    // 支付取消，库存退回
            case ORDER_STATUS_REFUND_SUCCESS: {   // 退款成功，库存退回
                try {
                    stockBack(updateOrder);
                } catch (Exception e) {
                    logger.error("库存+1失败, e:" + e.getMessage());
                    throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
                }
                break;
            }
            case ORDER_STATUS_COOPERATING_OVERTIME: { // 拼团超时，退库存
                try {
                    stockBack(updateOrder);
                } catch (Exception e) {
                    logger.error("库存+1失败, e:" + e.getMessage());
                    throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
                }
                break;
            }
            case ORDER_STATUS_COOPERATING_CANCEL: {   // 拼团取消，退库存
                try {
                    stockBack(updateOrder);
                } catch (Exception e) {
                    logger.error("库存+1失败, e:" + e.getMessage());
                    throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
                }
                break;
            }
            case ORDER_STATUS_COOPERATING_COMPLETE: {  // 拼团完成，退库存
                try {
                    stockBack(updateOrder);
                } catch (Exception e) {
                    logger.error("库存+1失败, e:" + e.getMessage());
                    throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
                }
                break;
            }
        }
        WxOrder refOrder = new WxOrder();
        refOrder.setId(updateOrder.getId());
        refOrder.setOrderStatus(enumOrderStatus.getCode());
        refOrder.setUpdateDate(currentDate);
        int ret = 0;
        try {
            ret = wxOrderMapper.updateById(refOrder);
        } catch (Exception e) {
            logger.error("订单状态更新失败, e:" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_UPDATE_ERR);
        }
        return ret;
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public void updateOrderStatus(WxOrder updateOrder) {
        if (updateOrder.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_OVERTIME.getCode()) ||
                updateOrder.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode()) ||
                updateOrder.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode()) ||
                updateOrder.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_FAILD.getCode()) ||
                updateOrder.getOrderStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_BREAK.getCode())) {
            try {
                stockBack(updateOrder);
            } catch (Exception e) {
                logger.error("拼团库存+1失败, e:" + e.getMessage());
                throw new MallinkException(ErrorCode.REMAIN_BACK_FAIL);
            }
        }
    }

    @Override
    public void updateOrderGroupStatusByCouponId(Long couponId, String tenantId, Integer orderStatus) {
        WxOrder updateOrder = new WxOrder();
        updateOrder.setTenantId(tenantId);
        updateOrder.setOrderStatus(orderStatus);
        updateOrder.setProductId(couponId);
        updateOrder.setUpdateDate(new Date());
        wxOrderMapper.updateOrderGroupStatusByCouponId(updateOrder);
    }

    @Override
    public void updateOrderGroupStatusByCouponChannelId(Long couponChannelId, String tenantId, Integer orderStatus) {
        WxOrder updateOrder = new WxOrder();
        updateOrder.setTenantId(tenantId);
        updateOrder.setOrderStatus(orderStatus);
        updateOrder.setCouponChannelId(couponChannelId);
        updateOrder.setUpdateDate(new Date());
        wxOrderMapper.updateOrderGroupStatusByCouponChannelId(updateOrder);
    }

    /**
     * 微信关闭订单
     */
    @Override
    public ResultData orderClose(WxOrder order) {
        // 1. get c appid
        WxAppinfo appInfo = wxAppinfoService.getCAppInfo(order.getTenantId());
        // 2. get pay order
        WxPayOrder payOrderQ = new WxPayOrder();
        payOrderQ.setTenantId(order.getTenantId());
        payOrderQ.setOrderId(order.getId());
        payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_STATUS_WAIT.getCode());
        List<WxPayOrder> payOrders = wxPayOrderMapper.selectList(new QueryWrapper(payOrderQ));

        // 3. wx pay order close
        for (WxPayOrder payOrder : payOrders) {
            try {
                wxPayOrderService.payOrderClose(appInfo, payOrder);
            } catch (Exception e) {
                logger.error("微信关单失败：" + e.getMessage());
                throw new MallinkException(ErrorCode.PAY_ORDER_ERROR);
            }
        }

        return new ResultData();
    }

    @Override
    public WxOrder getById(Long id) {
        return wxOrderMapper.selectById(id);
    }

    @Override
    public void saveOrUpdate(WxOrder record) {
        if (record.getId() == null) {
            //record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            final IdWorker idWorker = IdWorker.get();
            record.setId(idWorker.nextId());
            wxOrderMapper.insert(record);
        } else {
            wxOrderMapper.updateById(record);
        }
    }

    @Override
    public void deleteById(Long id) {
        wxOrderMapper.deleteById(id);
    }

    @Override
    public List<WxOrder> findList(WxOrder record) {
        return wxOrderMapper.findList(record);
    }

    @Override
    public PageInfo<WxOrderCouponVo> listCUserVoAsPage(WxOrder record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findListOfCUser(record));
    }

    @Override
    public WxOrderCouponVo detailCUserVo(WxOrder record) {
        return wxOrderMapper.selectDetailOfCUser(record);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public void shareForMicroPay(String tenantId, Long orderId, Long payOrderId) {
        // 微信分账
        try {
            WxPayOrder wxPayOrder = new WxPayOrder();
            wxPayOrder.setTenantId(tenantId);
            wxPayOrder.setId(payOrderId);
            wxPayOrder.setOrderId(orderId);
            wxPayOrder.setPayOrderStatus(EnumPayStatus.PAY_STATUS_SUCCESS.getCode());
            wxPayOrder = wxPayOrderMapper.selectOne(new QueryWrapper(wxPayOrder));
            WxOrder wxOrder = wxOrderMapper.selectById(orderId);
            WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById(wxOrder.getProductId());

            if (wxPayOrder != null && wxMerchantBUser != null &&
                    wxPayOrder.getShare().equals(EnumPayShare.YES.getCode())) {
                WxSharingOrderDto sharingOrder = new WxSharingOrderDto();
                sharingOrder.setCUserId(wxPayOrder.getCUserId());
                sharingOrder.setMerchantId(wxMerchantBUser.getMerchantId());
                sharingOrder.setType(EnumProfitSharingOrderType.PROFIT_SHARING_SINGLE.getCode());
                sharingOrder.setPayAmount(wxPayOrder.getPayAmount());
                sharingOrder.setRateAmount(wxPayOrder.getRateAmount());
                sharingOrder.setOrderId(wxPayOrder.getId());
                sharingOrder.setPayTimeStart(wxPayOrder.getPayTimeStart());
                sharingOrder.setPayTimeEnd(wxPayOrder.getPayTimeEnd());
                sharingOrder.setTenantId(wxPayOrder.getTenantId());
                sharingOrder.setTransactionId(wxPayOrder.getTransactionId());
                sharingOrder.setShareAmount(wxPayOrder.getShareAmount());
                ResultData resultData = wxProfitSharingOrderService.createSharingOrder(sharingOrder);
            } else {
                logger.error("微信分账: 未找到payorder or merchant at orderid-" + orderId);
            }
        } catch (MallinkException e) {
            logger.error("微信分账: " + e.getMessage());
        }
    }

    @Override
    public PageInfo<WxOrder> listOrderAsPage(WxOrderQueryVo record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findListOrder(record));
    }

    @Override
    public Map<String, Object> queryOrderSummary(String tenantId) {
        Map<String, Object> result = new HashMap<>();
        queryOrderCount(tenantId, result);
        queryOrderSummary(tenantId, result);
        return result;
    }

    public void queryMerchantCount(String tenantId, Map<String, Object> result) {
        String systemTime = DateUtils.getSystemTime("yyyy-MM-dd");
        //全部商户个数
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        String thirtyTime = DateUtils.getTimeBefore(29, new Date());
        params.put("startdate", thirtyTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long allMerchantCount = wxOrderMapper.queryOrderForMerchantCount(params);
        result.put("allMerchantCount", allMerchantCount);
        //今日
        params.put("startdate", systemTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long todayMerchantCount = wxOrderMapper.queryOrderForMerchantCount(params);
        result.put("todayMerchantCount", todayMerchantCount);
        //昨日
        String yesterday = DateUtils.getTimeBefore(1, new Date());
        params.put("startdate", yesterday + " 00:00:00");
        params.put("enddate", yesterday + " 23:59:59");
        Long yesterdayMerchantCount = wxOrderMapper.queryOrderForMerchantCount(params);
        result.put("yesterdayMerchantCount", yesterdayMerchantCount);
        //上周
        String lastweek = DateUtils.getTimeBefore(7, new Date());
        params.put("startdate", lastweek + " 00:00:00");
        params.put("enddate", lastweek + " 23:59:59");
        Long lastweekMerchantCount = wxOrderMapper.queryOrderForMerchantCount(params);
        result.put("lastweekMerchantCount", lastweekMerchantCount);
        //商户数日环比
        if (yesterdayMerchantCount > 0) {
            double hbd = (double) (todayMerchantCount - yesterdayMerchantCount) / yesterdayMerchantCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentMerchant", hb + "%");
        } else {
            result.put("increasedPercentMerchant", "--");
        }
        //商户数周同比
        if (lastweekMerchantCount > 0) {
            double hbd = (double) (todayMerchantCount - lastweekMerchantCount) / lastweekMerchantCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentWeekMerchant", hb + "%");
        } else {
            result.put("increasedPercentWeekMerchant", "--");
        }
    }

    public void queryOrderSummary(String tenantId, Map<String, Object> result) {
        String systemTime = DateUtils.getSystemTime("yyyy-MM-dd");
        //总数
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        String thirtyTime = DateUtils.getTimeBefore(29, new Date());
        params.put("startdate", thirtyTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        params.put("order_status", "1");
        Long allPayOrderSummary = wxOrderMapper.queryOrderForSum(params);
        params.put("order_status", "4");
        Long allRefundOrderSummary = wxOrderMapper.queryOrderForSum(params);
        result.put("allRefundOrderSummary", allRefundOrderSummary);
        Long allOrderSummary = allPayOrderSummary - allRefundOrderSummary;
        result.put("allOrderSummary", allPayOrderSummary);
        //今日
        params.put("startdate", systemTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        params.put("order_status", "1");
        Long todayPayOrderSummary = wxOrderMapper.queryOrderForSum(params);
        params.put("order_status", "4");
        Long todayRefundOrderSummary = wxOrderMapper.queryOrderForSum(params);
        result.put("todayRefundOrderSummary", todayRefundOrderSummary);
        result.put("todayOrderSummary", todayPayOrderSummary);
        //昨日
        String yesterday = DateUtils.getTimeBefore(1, new Date());
        params.put("startdate", yesterday + " 00:00:00");
        params.put("enddate", yesterday + " 23:59:59");
        params.put("order_status", "1");
        Long yesterdayPayOrderSummary = wxOrderMapper.queryOrderForSum(params);
        params.put("order_status", "4");
        Long yesterdayRefundOrderSummary = wxOrderMapper.queryOrderForSum(params);
        result.put("yesterdayRefundOrderSummary", yesterdayRefundOrderSummary);
        result.put("yesterdayOrderSummary", yesterdayPayOrderSummary);
        //上周
        String lastweek = DateUtils.getTimeBefore(7, new Date());
        params.put("startdate", lastweek + " 00:00:00");
        params.put("enddate", lastweek + " 23:59:59");
        params.put("order_status", "1");
        Long lastweekPayOrderSummary = wxOrderMapper.queryOrderForSum(params);
        params.put("order_status", "4");
        Long lastweekRefundOrderSummary = wxOrderMapper.queryOrderForSum(params);
        result.put("lastweekRefundOrderSummary", lastweekRefundOrderSummary);
        result.put("lastweekOrderSummary", lastweekPayOrderSummary);
        //商户数日环比
        if (yesterdayPayOrderSummary > 0) {
            double hbd = (double) (todayPayOrderSummary - yesterdayPayOrderSummary) / yesterdayPayOrderSummary * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentSummary", hb + "%");
        } else {
            result.put("increasedPercentSummary", "--");
        }
        //商户数周同比
        if (lastweekPayOrderSummary > 0) {
            double hbd = (double) (todayPayOrderSummary - lastweekPayOrderSummary) / lastweekPayOrderSummary * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentWeekSummary", hb + "%");
        } else {
            result.put("increasedPercentWeekSummary", "--");
        }
    }

    public void queryOrderCount(String tenantId, Map<String, Object> result) {
        String systemTime = DateUtils.getSystemTime("yyyy-MM-dd");
        //总数
        Map<String, Object> params = new HashMap<>();
        params.put("tenantId", tenantId);
        String thirtyTime = DateUtils.getTimeBefore(29, new Date());
        params.put("startdate", thirtyTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long allOrderCount = wxOrderMapper.queryOrderForCount(params);
        result.put("allOrderCount", allOrderCount);
        //今日
        params.put("startdate", systemTime + " 00:00:00");
        params.put("enddate", systemTime + " 23:59:59");
        Long todayOrderCount = wxOrderMapper.queryOrderForCount(params);
        result.put("todayOrderCount", todayOrderCount);
        //昨日
        String yesterday = DateUtils.getTimeBefore(1, new Date());
        params.put("startdate", yesterday + " 00:00:00");
        params.put("enddate", yesterday + " 23:59:59");
        Long yesterdayOrderCount = wxOrderMapper.queryOrderForCount(params);
        result.put("yesterdayOrderCount", yesterdayOrderCount);
        //上周
        String lastweek = DateUtils.getTimeBefore(7, new Date());
        params.put("startdate", lastweek + " 00:00:00");
        params.put("enddate", lastweek + " 23:59:59");
        Long lastweekOrderCount = wxOrderMapper.queryOrderForCount(params);
        result.put("lastweekOrderCount", lastweekOrderCount);
        //订单数日环比
        if (yesterdayOrderCount > 0) {
            double hbd = (double) (yesterdayOrderCount - yesterdayOrderCount) / yesterdayOrderCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentCount", hb + "%");
        } else {
            result.put("increasedPercentCount", "--");
        }
        //订单数周同比
        if (lastweekOrderCount > 0) {
            double hbd = (double) (yesterdayOrderCount - lastweekOrderCount) / lastweekOrderCount * 100;
            double hb = new BigDecimal(hbd).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            result.put("increasedPercentWeekCount", hb + "%");
        } else {
            result.put("increasedPercentWeekCount", "--");
        }
    }

    /**
     * 砍价
     */
    @Override
    public PageInfo<WxOrderCouponPressVo> listPressVoAsPage(WxOrder record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxOrderMapper.findListOfPress(record));
    }

    @Override
    public WxOrderCouponPressVo detailPressVo(WxOrder record) {
        return wxOrderMapper.selectDetailOfPress(record);
    }

    @Override
    public void updateStatusByPressCouponId(Long couponId, String tenantId, int orderStatus) {
        WxOrder updateOrder = new WxOrder();
        updateOrder.setTenantId(tenantId);
        updateOrder.setOrderStatus(orderStatus);
        updateOrder.setProductId(couponId);
        updateOrder.setUpdateDate(new Date());
        wxOrderMapper.updateStatusByPressCouponId(updateOrder);
    }

    @Override
    public WxOrder saveOrderForCoupon(WxCUser user, WxCoupon coupon, OrderSaveDto orderSaveDto, boolean isPress) {
        WxOrder order = null;
        if (checkCouponIsFree(coupon)) {
            // 免费券
            order = saveFreeOrderForCoupon(user, coupon, orderSaveDto.getCouponChannelId(), orderSaveDto.getFormId(), null);
            if (order != null) {
                // 6. 下订单完成，发送内部消息
                // 下订单完成，发送内部消息
                try {
                    sendOrderSuccessActionMsg(order);
                } catch (Exception e) {
                    logger.error("内部消息发送失败: " + e.getMessage());
                    throw new MallinkException(ErrorCode.MSG_INSIDE_ERROR);
                }
            }
        } else {
            // 有价券
            order = saveNoFreeOrderForCoupon(user, coupon, orderSaveDto.getCouponChannelId(), isPress, orderSaveDto.getOrderGroupId(), orderSaveDto.getFormId());
        }
        // couponActionLog
        try {
            wxCouponActionLogService.addOne(user.getTenantId(), order.getProductId(), order.getOrderNumber(), EnumCouponSendSendType.ACTIVE.getCode(), orderSaveDto.getCouponChannelId());
        } catch (Exception e) {
            // 库存恢复
            stockBack(order);
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }
        return order;
    }

    @Override
    public boolean checkCouponIsFree(WxCoupon coupon) {
        return coupon.getSalePrice() == 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxOrder saveFreeOrderForCoupon(WxCUser user, WxCoupon coupon, Long couponChannelId, String formId, Long couponPasswordId) {
        // 1. check user info and coupon info
        userCouponMerchantCheck(user, coupon);
        if (coupon.checkIsCreditCoupon()) {
            //若用户剩余积分比积分售价低则不能支付
            if (user.getCredit() == null || user.getCredit() < coupon.getCreditPrice()) {
                throw new MallinkException(ErrorCode.CREDIT_NOT_ENOUGH);
            }
        }
        // 2. 减库存操作
        String couponIdStr = String.valueOf(coupon.getId());
        stockReduce(user, coupon, couponIdStr);

        // 3. 当积分券或者积分停车券时 则进行积分支付
        Integer orderType;
        if (coupon.checkIsCreditCoupon()) {
            creditPay(user, coupon);
            orderType = EnumOrderType.CREDIT.getCode();
        } else {
            orderType = EnumOrderType.COUPON.getCode();
        }

        // 4. 保存Order
        WxOrder record = new WxOrder();
        record.setCouponChannelId(couponChannelId);
        record.setType(orderType);
        record.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PAYMENT_SUCCESS.getCode());
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setPayment(0);
        record.setFormId(formId);
        record.setOrderGroupId(0L);
        try {
            saveFreeOrder(record, user, coupon);
        } catch (Exception e) {
            logger.error("下订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }

        // 5. 创建couponOrder
        try {
            createCouponOrder(record, user, coupon, couponPasswordId);
        } catch (Exception e) {
            logger.error("couponOrder失败：" + e.getMessage());
            throw new MallinkException(ErrorCode.COUPON_ORDER_SAVE_ERR);
        }
        return record;
    }

    /**
     * 保存订单-免费
     *
     * @param record
     * @param user
     * @param coupon
     */
    private void saveFreeOrder(WxOrder record, WxCUser user, WxCoupon coupon) {
        Date curr = new Date();
        // body
        String bodyStr = "";
        try {
            bodyStr = Utility.substring(coupon.getTitle(), Math.min(62, coupon.getTitle().getBytes().length), "utf-8");
        } catch (Exception e) {
            logger.error("body:" + e.getMessage());
            bodyStr = "券" + '-' + EnumCouponType.getEnum(coupon.getType());
        }

        final IdWorker idWorker = IdWorker.get();
        Long orderNumber = idWorker.nextId();
        record.setId(orderNumber);
        record.setTenantId(user.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setProductId(coupon.getId());
        record.setCUserId(user.getId());
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setDetail(bodyStr);
        record.setCreateDate(curr);
        record.setUpdateDate(curr);
        // 保存订单
        wxOrderMapper.insert(record);
    }

    private void userCouponMerchantCheck(WxCUser user, WxCoupon coupon) throws MallinkException {
        // 检查用户
        if (user == null) {
            logger.error("用户不存在");
            throw new MallinkException(ErrorCode.USER_IS_EMPTY);
        }
        // 检查券
        if (coupon == null) {
            logger.error("券不存在");
            throw new MallinkException(ErrorCode.COUPON_IS_EMPTY);
        }
        // 检查券状态
        if (coupon.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode())) {
            logger.error("券已下架, couponId: " + coupon.getId());
            throw new MallinkException(ErrorCode.COUPON_ORDER_IS_INVALID);
        }
        // 检查券商户信息
        if (!isCouponMerchantValid(coupon.getId())) {
            logger.error("商户不存在, couponId: " + coupon.getId());
            throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
        }
        // 检查 优惠券 库存
        if (coupon.getRemainInventory() <= 0) {
            logger.error("此券库存为0, couponId: " + coupon.getId());
            throw new MallinkException(ErrorCode.REMAIN_IS_EMPTY);
        }
    }

    private void creditPay(WxCUser user, WxCoupon coupon) {
        //-------此处为【积分支付】记录增加积分操作-------
        WxCreditHistory creditHistory = new WxCreditHistory();
        //记录操作人类型 操作人id
        if (user.getOperatorType() == EnumUserType.MALLUSER.getCode()) {
            creditHistory.setOperatorType(EnumUserType.MALLUSER.getCode());
            creditHistory.setOperatorId(user.getOperatorId());
        } else {
            creditHistory.setOperatorType(EnumUserType.CUSER.getCode());
            creditHistory.setOperatorId(user.getId());
        }
        creditHistory.setCreditNum(coupon.getCreditPrice());
        creditHistory.setCUserId(user.getId());
        creditHistory.setTenantId(user.getTenantId());
        creditHistory.setCreditType(EnumScoreType.CHANGE_CREDIT.getCode());
        creditHistory.setCouponId(coupon.getId());
        //如果券与商户一对一 则直接将消费商户更新为此商户 若一对多 则消费商户显示多商户
        setMerchantId(coupon, creditHistory);
        wxCreditHistoryService.saveOrUpdate(creditHistory);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
    public WxOrder saveNoFreeOrderForCoupon(WxCUser user, WxCoupon coupon, Long couponChannelId, boolean isPress, Long orderGroupId, String formId) {
        // 1. check user info and coupon info
        userCouponMerchantCheck(user, coupon);
        if (coupon.checkIsCreditCoupon()) {
            //若用户剩余积分比积分售价低则不能支付
            if (user.getCredit() == null || user.getCredit() < coupon.getCreditPrice()) {
                throw new MallinkException(ErrorCode.CREDIT_NOT_ENOUGH);
            }
        }

        // 2. 拼团检查
        if (isOrderGroup(orderGroupId)) {
            checkOrderGroup(user, orderGroupId);
        }
        String couponIdStr = String.valueOf(coupon.getId());
        // 3. 减库存操作
        stockReduce(user, coupon, couponIdStr);

        // 3. 当积分券或者积分停车券时 则进行积分支付
        Integer orderType;
        if (coupon.checkIsCreditCoupon()) {
            creditPay(user, coupon);
            orderType = EnumOrderType.CREDIT.getCode();
        } else {
            orderType = EnumOrderType.COUPON.getCode();
        }

        // 4. 保存订单
        Long orderNumber;
        // 4.1 券价格
        int payment = coupon.getSalePrice();
        Integer orderStatus = EnumOrderStatus.ORDER_STATUS_PENDING_PAYMENT.getCode();
        if (isPress || coupon.getType().equals(EnumCouponType.COUPON_PRESS.getCode())) {
            // 砍价券 初始是全价即面额
            payment = coupon.getPrice();
        }
        if (coupon.getType().equals(EnumCouponType.COUPON_GROUP.getCode())) {
            if (orderGroupId == null) {
                // 拼团券 初始是全价即面额
                payment = coupon.getPrice();
            } else {
                orderStatus = EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode();
            }
        }

        // 4.2 保存订单
        WxOrder record = new WxOrder();
        record.setType(orderType);
        record.setCouponChannelId(couponChannelId);
        record.setOrderGroupId(orderGroupId);
        record.setFormId(formId);
        record.setPayment(payment);
        record.setOrderStatus(orderStatus);
        try {
            orderNumber = saveNoFreeOrder(record, user, coupon, isPress);
        } catch (Exception e) {
            logger.error("保存订单：" + e.getMessage());
            throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
        }

        if (isPress) {
            // 5. 第一次砍价
            try {
                firstPress(record, user, coupon, orderNumber);
            } catch (Exception e) {
                logger.error("第一次砍价失败：" + e.getMessage());
                throw new MallinkException(ErrorCode.ORDER_SAVE_ERR);
            }
        }
        return record;
    }

    /**
     * 初始砍价
     *
     * @param record
     * @param user
     * @param coupon
     * @param orderNumber
     */
    private void firstPress(WxOrder record, WxCUser user, WxCoupon coupon, Long orderNumber) {
        // 保存砍价信息
        int total = coupon.getPrice() - coupon.getSalePrice();
        int left_total = total;
        WxOrderPress orderPress = new WxOrderPress();
        orderPress.setId(IdWorker.get().nextId());
        orderPress.setCouponId(record.getProductId());
        orderPress.setOrderId(orderNumber);
        orderPress.setUserId(user.getId());
        orderPress.setCreateDate(new Date());
        orderPress.setFirst(EnumOrderPressType.FIRST.getCode());
        int lPressValue = PressUtils.stateLessPressValue(total, left_total, coupon.getPressLimitNum(), 0);
        orderPress.setPressValue(lPressValue);
        wxOrderPressMapper.insert(orderPress);
        // 更新订单砍价信息
        WxOrder orderUpdatePress = new WxOrder();
        orderUpdatePress.setId(record.getId());
        orderUpdatePress.setPressCurrentNum(1);
        orderUpdatePress.setPressCurrentValue(left_total - orderPress.getPressValue());
        orderUpdatePress.setOrderStatus(EnumOrderStatus.ORDER_STATUS_PRESSING.getCode());
        orderUpdatePress.setUpdateDate(new Date());
        wxOrderMapper.updateById(orderUpdatePress);
    }

    private Long saveNoFreeOrder(WxOrder record, WxCUser user, WxCoupon coupon, boolean isPress) {
        Long orderNumber;
        Date curr = new Date();

        // body
        // tenant_id + merchant_id + title + subtitle
        String bodyStr = "";
        try {
            bodyStr = Utility.substring(coupon.getTitle(), Math.min(62, coupon.getTitle().getBytes().length), "utf-8");
        } catch (Exception e) {
            logger.error("body:" + e.getMessage());
            bodyStr = "券-" + EnumCouponType.getEnum(coupon.getType()).getMessage();
        }
        final IdWorker idWorker = IdWorker.get();
        orderNumber = idWorker.nextId();
        record.setId(orderNumber);
        record.setTenantId(user.getTenantId());
        record.setOrderNumber(orderNumber);
        record.setProductId(coupon.getId());
        //record.setType(EnumOrderType.COUPON.getCode());
        record.setCUserId(user.getId());
        record.setPaymentType(EnumPayType.PAY_PAYMENT.getCode());
        record.setDetail(bodyStr);
        record.setUpdateDate(curr);
        record.setCreateDate(curr);
        if (isPress) {
            // 初始砍价信息
            record.setPressCurrentNum(0);
            // 砍价券过期时间取券的过期时间和砍价限制时间中时间小的那个
            Date pressEndDate = DateUtils.getHourTimeAfter(coupon.getPressLimitHours(), new Date());
            if (pressEndDate.after(coupon.getValidEndDate()))
                pressEndDate = coupon.getValidEndDate();
            record.setPressEndDate(pressEndDate);
            record.setPressCurrentValue(coupon.getPrice() - coupon.getSalePrice());
        }
        wxOrderMapper.insert(record);
        return orderNumber;
    }

    private void checkOrderGroup(WxCUser user, Long orderGroupId) {
        WxOrderGroup group = wxOrderGroupMapper.selectById(orderGroupId);
        if (group.getStatus().equals(EnumOrderStatus.ORDER_STATUS_COOPERATING_COMPLETE.getCode())) {
            logger.error("下订单拼团人数已满>>>" + orderGroupId);
            throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_FINISHED);
        }
        WxOrder order = new WxOrder();
        order.setOrderGroupId(group.getId());
        order.setCUserId(user.getId());
        order.setOrderStatus(EnumOrderStatus.ORDER_STATUS_COOPERATING_UNPAID.getCode());
        long count = wxOrderMapper.selectCount(new QueryWrapper(order));
        if (count > 0) {
            logger.error("重复的拼团>>>" + orderGroupId);
            throw new MallinkException(ErrorCode.ORDER_GROUP_COOPERATING_UNPAID);
        }
    }

    private boolean isOrderGroup(Long orderGroupId) {
        return orderGroupId != null && !orderGroupId.equals(0L);
    }


}
