package com.sckw.order.serivce;

import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.contract.api.model.dto.res.ContractCommonInfoResDto;
import com.sckw.core.common.enums.enums.DictTypeEnum;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.exception.CustomPromptException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.ClientTypeEnum;
import com.sckw.core.model.enums.CooperateTypeEnum;
import com.sckw.core.model.enums.OrderRuleEnum;
import com.sckw.core.model.enums.RedisOrderGenerateEnum;
import com.sckw.core.utils.*;
import com.sckw.core.web.constant.HttpStatus;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.HttpResult;
import com.sckw.manage.api.RemoteManageService;
import com.sckw.manage.api.model.dto.res.FindEntCooperateResVo;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.order.api.model.TradeOrderCountStatisticsDTO;
import com.sckw.order.dao.KwoTradeOrderMapper;
import com.sckw.order.enums.*;
import com.sckw.order.model.*;
import com.sckw.order.model.dto.OrderCheckDTO;
import com.sckw.order.model.dto.WbTOrderExcelStsReqDTO;
import com.sckw.order.model.dto.WbTOrderExcelStsResDTO;
import com.sckw.order.model.vo.req.*;
import com.sckw.order.model.vo.res.*;
import com.sckw.payment.api.dubbo.PayCenterDubboService;
import com.sckw.payment.api.dubbo.PaymentDubboService;
import com.sckw.payment.api.model.constant.ChannelEnum;
import com.sckw.payment.api.model.dto.WalletDto;
import com.sckw.payment.api.model.dto.common.R;
import com.sckw.product.api.dubbo.GoodsInfoService;
import com.sckw.product.api.model.GoodsDetail;
import com.sckw.product.api.model.KwpGoods;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.stream.enums.MessageEnum;
import com.sckw.stream.model.SckwBusSum;
import com.sckw.stream.model.SckwMessage;
import com.sckw.stream.model.UserInfo;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.AreaTreeFrontResDto;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.system.api.model.dto.res.KwsRoleResDto;
import com.sckw.system.api.model.dto.res.UserCacheResDto;
import com.sckw.transport.api.dubbo.TransportService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @desc: 交易订单（采购订单/销售订单）service
 * @author: yzc
 * @date: 2023-06-25 14:28
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class KwoTradeOrderService {

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteSystemService remoteSystemService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteManageService remoteManageService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private GoodsInfoService goodsInfoService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteContractService remoteContractService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private PayCenterDubboService payCenterDubboService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private PaymentDubboService paymentDubboService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private TransportService transportDubboService;

    private final KwoTradeOrderMapper kwoTradeOrderMapper;
    private final StreamBridge streamBridge;
    private final KwoTradeOrderAddressService kwoTradeOrderAddressService;
    private final KwoTradeOrderUnitService kwoTradeOrderUnitService;
    private final KwoTradeOrderGoodsService kwoTradeOrderGoodsService;
    private final KwoTradeOrderContractService kwoTradeOrderContractService;
    private final KwoTradeOrderTrackService kwoTradeOrderTrackService;

    @Value("${url.order.list.valet.pc}")
    private String pcValetListUrl;

    @Value("${url.order.list.valet.app}")
    private String appValetListUrl;

    @Value("${url.order.list.purchase.pc}")
    private String pcPurchaseListUrl;

    @Value("${url.order.list.purchase.app}")
    private String appPurchaseListUrl;

    /**
     * @desc: 采购下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderDraft(PurchaseOrderDraftParam param) {
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId())
                .setTOrderNo(getOrderNo())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null)
                .setSource(OrderSourceEnum.PURCHASE.getType()).setStatus(OrderStatusEnum.SAVED.getCode());
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
    }

    /**
     * @desc: 添加其他订单信息
     * @author: yzc
     * @date: 2023-07-13 8:53
     * @Param tradeOrder:
     * @Param param:
     * @Param isUpdate:
     * @return: void
     */
    private void addOtherOrderInfo(KwoTradeOrder tradeOrder, ValetOrderParam param, Boolean isUpdate) {
        Long id = tradeOrder.getId();
        String tOrderNo = tradeOrder.getTOrderNo();
        SckwTradeOrder order = new SckwTradeOrder();
        order.setFirmName(LoginUserHolder.getEntName())
                .setCreateByName(LoginUserHolder.getUserName())
                .setUpdateByName(LoginUserHolder.getUserName())
                .setTOrderId(id)
                .setAssociateStatement(0)
                .setPrice(tradeOrder.getPrice().doubleValue())
                .setAmount(tradeOrder.getAmount().doubleValue())
                .setEntrustAmount(tradeOrder.getEntrustAmount().doubleValue())
                .setActualAmount(tradeOrder.getActualAmount().doubleValue());

        BeanUtils.copyProperties(tradeOrder, order);
        //商品信息
        kwoTradeOrderGoodsService.delByOrderId(id);
        GoodsInfo goodsInfo = param.getGoodsInfo();
        KwoTradeOrderGoods goods = BeanUtils.copyProperties(goodsInfo, KwoTradeOrderGoods.class);
        if (Objects.nonNull(goods) && Objects.nonNull(goods.getGoodsId())) {
            GoodsDetail goodsDetail = goodsInfoService.getDetailById(goods.getGoodsId());
            if (Objects.isNull(goodsDetail) || !Objects.equals(goodsDetail.getStatus(), 1)
                    || Objects.equals(goodsDetail.getDelFlag(), Global.YES)) {
                throw new BusinessException("商品不存在或已下架！");
            }
            goods.setTOrderId(id).setTOrderNo(tOrderNo).setGoodsType(goodsDetail.getGoodsType());
            kwoTradeOrderGoodsService.insert(goods);
            order.setGoodsId(goodsDetail.getId()).setUnit(goodsDetail.getUnit()).setUnitPrice(goods.getUnitPrice().doubleValue())
                    .setGoodsName(goodsDetail.getName()).setGoodsType(goodsDetail.getGoodsType()).setGoodsCode(goodsDetail.getCode())
                    .setGoodsTaxRate(goodsDetail.getTaxRate()).setGoodsSpec(goodsDetail.getSpec()).setGoodsThumb(goodsDetail.getThumb());
        }
        if (Objects.isNull(order.getUnitPrice())) {
            order.setUnitPrice(BigDecimal.ZERO.doubleValue());
        }
        //单位信息
        kwoTradeOrderUnitService.delByOrderId(id);
        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollectionUtils.isNotEmpty(unitInfos)) {
            List<KwoTradeOrderUnit> list = new ArrayList<>(unitInfos.size());
            List<Long> entIds = unitInfos.stream().map(UnitInfo::getEntId).distinct().toList();
            Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
            unitInfos.forEach(e -> {
                EntCacheResDto ent = entMap.get(e.getEntId());
                if (Objects.isNull(ent)) {
                    throw new BusinessException("企业:" + e.getFirmName() + "的一级企业信息不存在！");
                }
                KwoTradeOrderUnit unit = BeanUtils.copyProperties(e, KwoTradeOrderUnit.class);
                unit.setTOrderId(id).setTOrderNo(tOrderNo).setTopEntId(ent.getId());
                list.add(unit);
                if (Objects.equals(e.getUnitType(), OrderUnitTypeEnum.PURCHASE.getType())) {
                    order.setProcureEntId(e.getEntId()).setProcureTopEntId(unit.getTopEntId()).setProcureFirmName(e.getFirmName())
                            .setProcureContacts(e.getContacts()).setProcurePhone(e.getPhone()).setProcureContactsId(e.getContactsId());
                } else {
                    order.setSupplyEntId(e.getEntId()).setSupplyTopEntId(unit.getTopEntId()).setSupplyFirmName(e.getFirmName())
                            .setSupplyContacts(e.getContacts()).setSupplyPhone(e.getPhone()).setSupplyContactsId(e.getContactsId());
                }
            });
            kwoTradeOrderUnitService.insertBatch(list);
        }
        //地址信息
        kwoTradeOrderAddressService.delByOrderId(id);
        List<AddressInfo> addressInfos = param.getAddressInfo();
        if (CollectionUtils.isNotEmpty(addressInfos)) {
            List<KwoTradeOrderAddress> list = new ArrayList<>(addressInfos.size());
            addressInfos.forEach(e -> {
                KwoTradeOrderAddress address = BeanUtils.copyProperties(e, KwoTradeOrderAddress.class);
                address.setTOrderId(id).setTOrderNo(tOrderNo);
                list.add(address);
                if (Objects.equals(e.getAddressType(), OrderAddressTypeEnum.LOAD.getType())) {
                    order.setLoadName(e.getName()).setLoadType(e.getType()).setLoadContacts(e.getContacts())
                            .setLoadPhone(e.getPhone()).setLoadCityCode(String.valueOf(e.getCityCode())).setLoadCityName(e.getCityName())
                            .setLoadDetailAddress(e.getDetailAddress()).setLoadLat(e.getLat()).setLoadLng(e.getLng());
                } else {
                    order.setUnloadName(e.getName()).setUnloadType(e.getType()).setUnloadContacts(e.getContacts())
                            .setUnloadPhone(e.getPhone()).setUnloadCityCode(String.valueOf(e.getCityCode())).setUnloadCityName(e.getCityName())
                            .setUnloadDetailAddress(e.getDetailAddress()).setUnloadLat(e.getLat()).setUnloadLng(e.getLng());
                }
            });
            kwoTradeOrderAddressService.insertBatch(list);
        }
        //合同信息
        kwoTradeOrderContractService.delByOrderId(id);
        ContractInfo contractInfo = param.getContractInfo();
        KwoTradeOrderContract contract = BeanUtils.copyProperties(contractInfo, KwoTradeOrderContract.class);
        if (Objects.nonNull(contract)) {
            contract.setTOrderId(id).setTOrderNo(tOrderNo);
            kwoTradeOrderContractService.insert(contract);
            BeanUtils.copyProperties(contractInfo, order);
        }
        //状态信息（草稿更新不加状态记录）
        if (!isUpdate || !Objects.equals(OrderStatusEnum.SAVED.getCode(), tradeOrder.getStatus())) {
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(id).setTOrderNo(tOrderNo).setStatus(tradeOrder.getStatus()).setRemark(tradeOrder.getRemark());
            kwoTradeOrderTrackService.insert(track);
        }
        int method = isUpdate ? 2 : 1;
        //存MongoDb
        saveMongoDb(method, order);
    }

    /**
     * @desc: mq保存mongodb
     * @author: yzc
     * @date: 2023-07-17 8:43
     * @Param method:
     * @Param order:
     * @return: void
     */
    private void saveMongoDb(Integer method, Object order) {
        SckwBusSum busSum = new SckwBusSum();
        busSum.setBusSumType("tradeOrder");
        busSum.setMethod(method);
        busSum.setObject(order);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }


    /**
     * @desc: 代客下单草稿
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addValetOrderDraft(ValetOrderDraftParam param) {
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId())
                .setTOrderNo(getOrderNo())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setUnit(Objects.nonNull(param.getGoodsInfo()) ? param.getGoodsInfo().getUnit() : null)
                .setSource(OrderSourceEnum.SALE.getType()).setStatus(OrderStatusEnum.SAVED.getCode());
        kwoTradeOrderMapper.insert(order);
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
    }

    /**
     * @desc: 采购下单提交
     * @author: yzc
     * @date: 2023-07-07 15:31
     * @Param param:
     * @return: void
     */
    public void addPurchaseOrderSubmit(PurchaseOrderParam param) {
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo.getPriceRangeId())) {
            throw new BusinessException("采购下单价格梯度信息不能为空！");
        }
        OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, param.getUnitInfo());
        orderCheck.setGoodsId(goodsInfo.getGoodsId()).setUnitPrice(goodsInfo.getUnitPrice())
                .setOrderSource(OrderSourceEnum.PURCHASE.getType());
        orderCheck(orderCheck, false);
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId())
                .setTOrderNo(getOrderNo())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setUnit(param.getGoodsInfo().getUnit())
                .setSource(OrderSourceEnum.PURCHASE.getType())
                .setStatus(OrderStatusEnum.WAIT_ACCEPTED.getCode());
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //添加订单其他信息
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
        //发送消息提醒
        submitOrderSendMsg(orderCheck, order.getTOrderNo());
    }

    /**
     * @desc: 提交订单发送message
     * @author: yzc
     * @date: 2023-09-01 14:35
     * @Param orderCheck:
     * @Param orderNo:
     * @return: void
     */
    private void submitOrderSendMsg(OrderCheckDTO orderCheck, String orderNo) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", orderNo);
        List<UserInfo> userInfos = new ArrayList<>();
        //提交人信息
        UserInfo createUser = new UserInfo();
        createUser.setUserId(LoginUserHolder.getUserId()).setEntId(LoginUserHolder.getEntId());
        userInfos.add(createUser);
        boolean flag = Objects.equals(orderCheck.getOrderSource(), OrderSourceEnum.PURCHASE.getType());
        UserInfo procureUser = orderCheck.getProcureUser();
        String procureFireName = orderCheck.getProcureFireName();
        UserInfo supplyUser = orderCheck.getSupplyUser();
        String supplyFireName = orderCheck.getSupplyFireName();
        //采购下单
        if (flag) {
            //给创建人及采购联系人发消息
            map.put("firmName", supplyFireName);
            if (!Objects.equals(procureUser.getUserId(), LoginUserHolder.getUserId())) {
                userInfos.add(procureUser);
            }
            sendMsg(MessageEnum.ORDER_INITIATE_PURCHASE, map, pcPurchaseListUrl, appPurchaseListUrl, userInfos);
            //给供应企业联系人发消息
            map.put("firmName", procureFireName);
            sendMsg(MessageEnum.ORDER_NEW_PENDING, map, pcValetListUrl, appValetListUrl, List.of(supplyUser));
        } else {
            //代客下单
            //给创建人及供应企业联系人发消息
            map.put("firmName", procureFireName);
            if (!Objects.equals(supplyUser.getUserId(), LoginUserHolder.getUserId())) {
                userInfos.add(supplyUser);
            }
            sendMsg(MessageEnum.ORDER_INITIATE_SALE, map, pcValetListUrl, appValetListUrl, userInfos);
            //给采购企业联系人发消息
            map.put("firmName", supplyFireName);
            sendMsg(MessageEnum.ORDER_NEW_VALET_MSG, map, pcPurchaseListUrl, appPurchaseListUrl, List.of(procureUser));
        }
    }

    /**
     * @desc: 发送消息
     * @author: yzc
     * @date: 2023-09-06 15:57
     * @Param msgEnum: 消息枚举
     * @Param params: 消息变量
     * @Param pcUrl: pc消息调转url
     * @Param appUrl: app消息调转url
     * @Param userInfos:  发送消息用户集合
     * @return: void
     */
    private void sendMsg(MessageEnum msgEnum, Map<String, Object> params, String pcUrl, String appUrl, List<UserInfo> userInfos) {
        Map<String, String> urls = new HashMap<>();
        urls.put(ClientTypeEnum.pc.getValue(), pcUrl);
        urls.put(ClientTypeEnum.app.getValue(), appUrl);
        SckwMessage msg = new SckwMessage(msgEnum);
        msg.setParams(params)
                .setMsgUrls(urls)
                .setUserInfos(userInfos)
                .setCreateBy(LoginUserHolder.getUserId());
        log.info("有新的提醒消息：{}", JSON.toJSONString(msg));
        streamBridge.send("sckw-message", JSON.toJSONString(msg));
    }

    /**
     * @desc: 获取采购销售顶级企业id
     * @author: yzc
     * @date: 2023-07-25 10:03
     * @Param orderCheck:
     * @Param unitInfo:
     * @return: void
     */
    private void getTopEnt(OrderCheckDTO orderCheck, List<UnitInfo> unitInfo) {
        List<Long> entIds = unitInfo.stream().map(UnitInfo::getEntId).toList();
        Map<Long, EntCacheResDto> entMap = remoteSystemService.queryEntTreeByIds(entIds);
        unitInfo.forEach(e -> {
            Long entId = e.getEntId();
            EntCacheResDto ent = entMap.get(entId);
            if (Objects.isNull(ent)) {
                log.error("企业：{}找不到对应一级企业信息", entId);
                throw new BusinessException("一级企业信息不存在！");
            }
            if (Objects.equals(e.getUnitType(), OrderUnitTypeEnum.PURCHASE.getType())) {
                UserInfo procureUser = new UserInfo();
                orderCheck.setProcureTopEntId(ent.getId());
                orderCheck.setProcureEntId(entId);
                orderCheck.setProcureFireName(e.getFirmName());
                procureUser.setUserId(e.getContactsId()).setEntId(ent.getId());
                orderCheck.setProcureUser(procureUser);
            } else {
                UserInfo supplyUser = new UserInfo();
                orderCheck.setSupplyTopEntId(ent.getId());
                orderCheck.setSupplyEntId(entId);
                orderCheck.setSupplyFireName(e.getFirmName());
                supplyUser.setUserId(e.getContactsId()).setEntId(ent.getId());
                orderCheck.setSupplyUser(supplyUser);
            }
        });
    }

    /**
     * @desc: 订单提交校验
     * @author: yzc
     * @date: 2023-07-14 14:46
     * @Param param: 订单校验参数
     * @Param isAcceptanceOrder: 是否受理订单
     * @return: void
     */
    private void orderCheck(OrderCheckDTO param, Boolean isAcceptanceOrder) {
        BigDecimal amount = param.getAmount();
        String trading = param.getTrading();
        BigDecimal price = param.getPrice();
        if (!isAcceptanceOrder) {
            if (price.compareTo(amount.multiply(param.getUnitPrice())) != 0) {
                throw new BusinessException("订单总金额不等于商品单价*订单总量！");
            }
            List<FindEntCooperateResVo> entCooperate;
            if (OrderSourceEnum.PURCHASE.getType().equals(param.getOrderSource())) {
                entCooperate = remoteManageService.findEntCooperate(param.getProcureEntId()
                        , param.getSupplyEntId(), CooperateTypeEnum.SUPPLIER.getCode());
            } else {
                entCooperate = remoteManageService.findEntCooperate(param.getSupplyEntId()
                        , param.getProcureEntId(), CooperateTypeEnum.PURCHASER.getCode());
            }
            if (CollectionUtils.isEmpty(entCooperate)) {
                throw new BusinessException("供采双方企业无合作关系！");
            }
        }
        KwpGoods goods = goodsInfoService.getGoodsById(param.getGoodsId());
        if (Objects.isNull(goods) || Objects.equals(goods.getDelFlag(), Global.YES) || !Objects.equals(goods.getStatus(), 1)) {
            throw new BusinessException("商品不存在或已下架！");
        }
        if (goods.getAmount().compareTo(amount) < 0) {
            throw new BusinessException("商品库存不足，请联系供应方！");
        }
        //支付方式预付款校验
        if (trading.startsWith("1")) {
            BigDecimal decimal = Objects.isNull(goods.getAdvancePrice()) ? BigDecimal.ZERO : goods.getAdvancePrice();
            BigDecimal advancePrice = decimal.multiply(new BigDecimal("10000"));
            //直接采购下单才校验预付款限额
            if (Objects.equals(param.getOrderSource(), OrderSourceEnum.PURCHASE.getType()) && price.compareTo(advancePrice) < 0) {
                throw new BusinessException("您的订单总额未达到预付限额，请确认");
            }
            R<List<WalletDto>> wallet = payCenterDubboService.wallet(param.getProcureTopEntId(), ChannelEnum.getByCode(trading), param.getSupplyTopEntId());
            if (Objects.isNull(wallet) || Objects.equals(wallet.getCode(), 0)) {
                throw new BusinessException("校验预付钱包异常，请联系管理员！");
            }
            List<WalletDto> data = wallet.getData();
            if (CollectionUtils.isEmpty(data)) {
                throw new BusinessException("检测尚未创建对应预付款清单，请先创建！");
            }
            long money = data.get(0).getApMoney();
            if (money < advancePrice.multiply(new BigDecimal("100")).longValueExact()) {
                throw new BusinessException("您的预付清单可用余额不足，请先充值！");
            }
        }
    }

    /**
     * @desc: 代客下单提交
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param param:
     * @return: void
     */
    public void addValetOrderSubmit(ValetOrderParam param) {
        OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, param.getUnitInfo());
        orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice())
                .setOrderSource(OrderSourceEnum.SALE.getType());
        orderCheck(orderCheck, false);
        ContractInfo contract = param.getContractInfo();
        contractCheck(contract);
        param.setContractInfo(contract);
        KwoTradeOrder order = BeanUtils.copyProperties(param, KwoTradeOrder.class);
        order.setEntId(LoginUserHolder.getEntId())
                .setTOrderNo(getOrderNo())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setUnit(param.getGoodsInfo().getUnit())
                .setSource(OrderSourceEnum.SALE.getType());
        String contractStatus = contract.getContractStatus();
        if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
        } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.EXECUTING.getCode());
        } else {
            throw new BusinessException("Invalid contract status");
        }
        kwoTradeOrderMapper.insert(order);
        //扣减库存
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //冻结金额
        if (param.getTrading().startsWith("1")) {
            HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(),
                    ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                throw new BusinessException(freezeResult.getMsg());
            }
        }
        addOtherOrderInfo(order, BeanUtils.copyProperties(param, ValetOrderParam.class), false);
        //发送消息提醒
        submitOrderSendMsg(orderCheck, order.getTOrderNo());
    }


    /**
     * 生成贸易订单号
     *
     * @return
     */
    private String getOrderNo() {
        Date date = new Date();
        String lockKey = String.format(RedisConstant.TORDER_NO_GENERATE_KEY, DateUtils.formatDateToYYMMDD(date));
        String key = OrderGenerateSeqNoUtils.getKey(RedisOrderGenerateEnum.TRADE_ORDER, OrderRuleEnum.TRADE_ORDER, date);
        try {
            if (Boolean.FALSE.equals(RedissonUtils.exists(key))) {
                if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
                    throw new BusinessException("业务繁忙，请稍后再试！");
                }
                DateTime dateTime = DateUtils.beginOfDay(date);
                String maxOrderNo = kwoTradeOrderMapper.getMaxOrderNoByDate(dateTime);
                if (StringUtils.isNotBlank(maxOrderNo)) {
                    Long maxNum = Long.valueOf(StringUtils.subStrFromIndexToEnd(maxOrderNo, 4));
                    RedissonUtils.setAtomicLong(key, maxNum, DateUtils.getSecondsDay());
                }
            }
            return OrderGenerateSeqNoUtils.getOtherSeqNo(RedisOrderGenerateEnum.TRADE_ORDER, OrderRuleEnum.TRADE_ORDER);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
    }

    /**
     * @desc: 合同校验
     * @author: yzc
     * @date: 2023-08-24 10:54
     * @Param contract:
     * @return: void
     */
    private void contractCheck(ContractInfo contract) {
        Map<Long, ContractCommonInfoResDto> map = remoteContractService.queryContractBaseInfo(List.of(contract.getContractId()));
        ContractCommonInfoResDto contractInfo = map.get(contract.getContractId());
        if (Objects.isNull(contractInfo)) {
            throw new BusinessException("不存在该合同信息！");
        }
        Integer status = contractInfo.getStatus();
        if (!Objects.equals(0, status) && !Objects.equals(1, status)) {
            throw new BusinessException("合同状态异常！");
        }
        contract.setContractName(contract.getContractName());
        contract.setContractNo(contractInfo.getContractCode());
        contract.setContractSigningWay(contractInfo.getSigningWayName());
        contract.setContractStatus(String.valueOf(status));
    }

    /**
     * @desc: 获取订单详情
     * @author: yzc
     * @date: 2023-08-18 11:18
     * @Param id:
     * @return: com.sckw.order.model.vo.res.OrderDetailRes
     */
    public OrderDetailRes getDetail(Long id) {
        OrderDetailRes detail = this.detail(id);
        List<KwoTradeOrderTrack> tracks = kwoTradeOrderTrackService.getByOrderId(id);
        if (CollectionUtils.isEmpty(tracks)) {
            return detail;
        }
        List<OrderProcess> orderProcesses = new ArrayList<>(tracks.size());
        List<Long> createBys = tracks.stream().map(KwoTradeOrderTrack::getCreateBy).distinct().toList();
        Map<Long, UserCacheResDto> map = remoteSystemService.queryUserCacheMapByIds(createBys);
        tracks.forEach(e -> {
            OrderProcess process = BeanUtils.copyProperties(e, OrderProcess.class);
            UserCacheResDto user = map.get(process.getCreateBy());
            if (Objects.nonNull(user)) {
                process.setCreateByName(user.getName());
                if (CollectionUtils.isNotEmpty(user.getRoleInfo())) {
                    List<String> roleNames = user.getRoleInfo().stream().map(KwsRoleResDto::getName).distinct().toList();
                    process.setRoleName(String.join(",", roleNames));
                }
            }
            process.setStatusLabel(OrderStatusEnum.getMsg(process.getStatus()));
            orderProcesses.add(process);
        });
        detail.setOrderProcess(orderProcesses);
        return detail;
    }

    /**
     * @desc: 订单详情
     * @author: yzc
     * @date: 2023-07-07 15:32
     * @Param id:
     * @return: com.sckw.order.model.vo.res.OrderDetail
     */
    public OrderDetailRes detail(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("不存在该订单！");
        }
        Map<String, Map<String, String>> dict = remoteSystemService.queryDictByType(
                List.of(DictTypeEnum.TRADE_TYPE.getType(), DictTypeEnum.PICKUP_TYPE.getType(),
                        DictTypeEnum.DELIVERY_TYPE.getType(), DictTypeEnum.TORDER_SOURCE.getType(), DictTypeEnum.TORDER_STATUS.getType(),
                        DictTypeEnum.PRODUCT_NAME_TYPE.getType(), DictTypeEnum.UNIT_TYPE.getType(), DictTypeEnum.TAX_RATE.getType(),
                        DictTypeEnum.TORDER_UNIT_TYPE.getType(), DictTypeEnum.TORDER_ADDRESS_TYPE.getType(), DictTypeEnum.ADDRESS_TYPE.getType()));
        Map<String, String> tradeMap = new HashMap<>();
        Map<String, String> pickupMap = new HashMap<>();
        Map<String, String> deleveryMap = new HashMap<>();
        Map<String, String> sourceMap = new HashMap<>();
        Map<String, String> statusMap = new HashMap<>();
        Map<String, String> prodcutNameMap = new HashMap<>();
        Map<String, String> unitMap = new HashMap<>();
        Map<String, String> taxRateMap = new HashMap<>();
        Map<String, String> orderUnitMap, orderAddressMap, addressMap;
        if (CollectionUtils.isNotEmpty(dict)) {
            tradeMap = dict.get(DictTypeEnum.TRADE_TYPE.getType());
            pickupMap = dict.get(DictTypeEnum.PICKUP_TYPE.getType());
            deleveryMap = dict.get(DictTypeEnum.DELIVERY_TYPE.getType());
            sourceMap = dict.get(DictTypeEnum.TORDER_SOURCE.getType());
            statusMap = dict.get(DictTypeEnum.TORDER_STATUS.getType());
            prodcutNameMap = dict.get(DictTypeEnum.PRODUCT_NAME_TYPE.getType());
            unitMap = dict.get(DictTypeEnum.UNIT_TYPE.getType());
            taxRateMap = dict.get(DictTypeEnum.TAX_RATE.getType());
            orderUnitMap = dict.get(DictTypeEnum.TORDER_UNIT_TYPE.getType());
            orderAddressMap = dict.get(DictTypeEnum.TORDER_ADDRESS_TYPE.getType());
            addressMap = dict.get(DictTypeEnum.ADDRESS_TYPE.getType());
        } else {
            orderUnitMap = new HashMap<>();
            orderAddressMap = new HashMap<>();
            addressMap = new HashMap<>();
        }
        //订单基本信息
        OrderDetailRes detail = BeanUtils.copyProperties(order, OrderDetailRes.class);
        UserCacheResDto createUser = remoteSystemService.queryUserCacheById(detail.getCreateBy());
        EntCacheResDto ent = remoteSystemService.queryEntCacheById(detail.getEntId());
        detail.setFirmName(Objects.isNull(ent) ? null : ent.getFirmName())
                .setCreateByName(Objects.isNull(createUser) ? null : createUser.getName())
                .setTradingLabel(CollectionUtils.isNotEmpty(tradeMap) ? tradeMap.get(detail.getTrading()) : null)
                .setPickupTypeLabel(CollectionUtils.isNotEmpty(pickupMap) ? pickupMap.get(detail.getPickupType()) : null)
                .setDeliveryTypeLabel(CollectionUtils.isNotEmpty(deleveryMap) ? deleveryMap.get(detail.getDeliveryType()) : null)
                .setSourceLabel(CollectionUtils.isNotEmpty(sourceMap) ? sourceMap.get(detail.getSource()) : null)
                .setStatusLabel(CollectionUtils.isNotEmpty(statusMap) ? statusMap.get(String.valueOf(detail.getStatus())) : null);
        //商品信息
        KwoTradeOrderGoods orderGoods = kwoTradeOrderGoodsService.getByOrderId(id);
        if (Objects.nonNull(orderGoods)) {
            KwpGoods goods = goodsInfoService.getGoodsById(orderGoods.getGoodsId());
            if (Objects.nonNull(goods)) {
                EntCacheResDto entCache = remoteSystemService.queryEntCacheById(goods.getEntId());
                GoodsInfoDetailRes goodsDetail = new GoodsInfoDetailRes();
                goodsDetail.setGoodsTypeLabel(CollectionUtils.isNotEmpty(prodcutNameMap) ? prodcutNameMap.get(goods.getGoodsType()) : null)
                        .setUnitLabel(CollectionUtils.isNotEmpty(unitMap) ? unitMap.get(goods.getUnit()) : null)
                        .setTaxRateLabel(CollectionUtils.isNotEmpty(taxRateMap) ? taxRateMap.get(goods.getTaxRate()) : null)
                        .setGoodsAmount(goods.getAmount())
                        .setGoodsId(goods.getId()).setCode(goods.getCode()).setName(goods.getName())
                        .setGoodsType(goods.getGoodsType()).setTaxRate(goods.getTaxRate()).setSpec(goods.getSpec())
                        .setUnit(goods.getUnit()).setPriceRangeId(orderGoods.getPriceRangeId()).setUnitPrice(orderGoods.getUnitPrice())
                        .setSkuId(orderGoods.getSkuId()).setCollectionUnitId(goods.getEntId()).setGoodsThumb(goods.getThumb())
                        .setPrepaidLimit(goods.getPrepaidLimit()).setAdvancePrice(goods.getAdvancePrice())
                        .setCollectionUnit(Objects.isNull(entCache) ? null : entCache.getFirmName());
                detail.setGoodsInfo(goodsDetail);
            }
        }

        //单位信息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(id);
        if (CollectionUtils.isNotEmpty(units)) {
            List<UnitInfoDetailRes> unitInfos = new ArrayList<>(units.size());
            units.forEach(e -> {
                UnitInfoDetailRes unit = BeanUtils.copyProperties(e, UnitInfoDetailRes.class);
                unit.setUnitTypeLabel(CollectionUtils.isNotEmpty(orderUnitMap) ? orderUnitMap.get(unit.getUnitType()) : null);
                unitInfos.add(unit);
            });
            detail.setUnitInfo(unitInfos);
        }
        //地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderId(id);
        if (CollectionUtils.isNotEmpty(addressList)) {
            List<AddressInfoDetailRes> addressInfoDetails = new ArrayList<>(addressList.size());
            addressList.forEach(e -> {
                AddressInfoDetailRes address = BeanUtils.copyProperties(e, AddressInfoDetailRes.class);
                address.setAddressTypeLabel(CollectionUtils.isNotEmpty(orderAddressMap) ? orderAddressMap.get(address.getAddressType()) : null);
                address.setTypeLabel(CollectionUtils.isNotEmpty(addressMap) ? addressMap.get(address.getType()) : null);
                addressInfoDetails.add(address);
            });
            detail.setAddressInfo(addressInfoDetails);
        }
        //合同信息
        KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(id);
        if (Objects.nonNull(contract)) {
            ContractInfo contractInfo = BeanUtils.copyProperties(contract, ContractInfo.class);
            Map<Long, ContractCommonInfoResDto> contractMap = remoteContractService.queryContractBaseInfo(List.of(contractInfo.getContractId()));
            ContractCommonInfoResDto contractRes = contractMap.get(contractInfo.getContractId());
            if (Objects.nonNull(contractRes)) {
                contractInfo.setContractName(contractRes.getContactName());
                contractInfo.setContractSigningWay(contractRes.getSigningWayName());
                contractInfo.setContractStatus(contractRes.getStatusName());
            }
            detail.setContractInfo(contractInfo);
        }
        return detail;
    }

    /**
     * @desc: 修改订单
     * @author: yzc
     * @date: 2023-07-07 15:34
     * @Param param:
     * @return: void
     */
    public void update(UpdateOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        String source = order.getSource();
        Integer status = order.getStatus();
        if ((!Objects.equals(status, OrderStatusEnum.SAVED.getCode()) && !Objects.equals(status, OrderStatusEnum.RETURNED.getCode()))
                && Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
            throw new BusinessException("采购下单只能修改已保存及已退回状态的订单！");
        }
        if (Objects.equals(source, OrderSourceEnum.SALE.getType()) && !Objects.equals(status, OrderStatusEnum.SAVED.getCode())) {
            throw new BusinessException("代客下单只能修改已保存状态的订单！");
        }
        if (!Objects.equals(0, order.getStatus())
                && kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), source)) {
            throw new BusinessException("无权限修改此订单！");
        }
        OrderCheckDTO orderCheck = new OrderCheckDTO();
        if (Objects.equals(param.getOperateType(), 1)) {
            checkParams(param, source);
            if (Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
                order.setStatus(OrderStatusEnum.WAIT_ACCEPTED.getCode());
            } else {
                ContractInfo contract = param.getContractInfo();
                contractCheck(contract);
                param.setContractInfo(contract);
                String contractStatus = contract.getContractStatus();
                if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
                    order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
                } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
                    order.setStatus(OrderStatusEnum.EXECUTING.getCode());
                } else {
                    throw new BusinessException("Invalid contract status");
                }
            }
            orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
            getTopEnt(orderCheck, param.getUnitInfo());
            orderCheck.setGoodsId(param.getGoodsInfo().getGoodsId()).setUnitPrice(param.getGoodsInfo().getUnitPrice())
                    .setOrderSource(source);
            orderCheck(orderCheck, false);
            //扣减库存
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(param.getGoodsInfo().getGoodsId(), param.getAmount());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
            //代客下单冻结金额
            if (Objects.equals(source, OrderSourceEnum.SALE.getType()) && param.getTrading().startsWith("1")){
                HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(),
                        ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
                if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                    throw new BusinessException(freezeResult.getMsg());
                }
            }
        }
        order.setAmount(param.getAmount()).setUnit(Objects.isNull(param.getGoodsInfo()) ? null : param.getGoodsInfo().getUnit())
                .setPrice(param.getPrice()).setTrading(param.getTrading()).setPickupType(param.getPickupType())
                .setDeliveryType(param.getDeliveryType())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setRemark(param.getRemark());
        LambdaUpdateWrapper<KwoTradeOrder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(KwoTradeOrder::getAmount, order.getAmount())
                .set(KwoTradeOrder::getUnit, order.getUnit())
                .set(KwoTradeOrder::getPrice, order.getPrice())
                .set(KwoTradeOrder::getTrading, order.getTrading())
                .set(KwoTradeOrder::getPickupType, order.getPickupType())
                .set(KwoTradeOrder::getDeliveryType, order.getDeliveryType())
                .set(KwoTradeOrder::getStartTime, order.getStartTime())
                .set(KwoTradeOrder::getEndTime, order.getEndTime())
                .set(KwoTradeOrder::getRemark, order.getRemark())
                .set(KwoTradeOrder::getStatus, order.getStatus())
                .eq(KwoTradeOrder::getId, order.getId());
        kwoTradeOrderMapper.update(null, wrapper);
        ValetOrderParam valetOrderParam = BeanUtils.copyProperties(param, ValetOrderParam.class);

        addOtherOrderInfo(order, valetOrderParam, true);
        //订单提交发送提醒消息
        if (Objects.equals(param.getOperateType(), 1)) {
            submitOrderSendMsg(orderCheck, order.getTOrderNo());
        }
    }


    private void checkParams(UpdateOrderParam param, String source) {
        if (Objects.isNull(param.getAmount()) || param.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单总量不能为空且必须大于零！");
        }
        if (Objects.isNull(param.getPrice()) || param.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单金额不能为空且必须大于零！");
        }
        if (StringUtils.isBlank(param.getTrading())) {
            throw new BusinessException("交易方式不能为空!");
        }
        if (StringUtils.isBlank(param.getPickupType())) {
            throw new BusinessException("提货方式不能为空!");
        }
        if (Objects.isNull(param.getStartTime())) {
            throw new BusinessException("开始时间不能为空！");
        }
        if (Objects.isNull(param.getEndTime())) {
            throw new BusinessException("结束时间不能为空！");
        }
        if (StringUtils.isBlank(param.getDeliveryType())) {
            throw new BusinessException("交付类型不能为空!");
        }
        ContractInfo contractInfo = param.getContractInfo();
        if (Objects.equals(source, OrderSourceEnum.SALE.getType())) {
            if (Objects.isNull(contractInfo)) {
                throw new BusinessException("代客下单合同信息不能为空");
            }
            if (Objects.isNull(contractInfo.getContractId())) {
                throw new BusinessException("合同id不能为空！");
            }
        }
        GoodsInfo goodsInfo = param.getGoodsInfo();
        if (Objects.isNull(goodsInfo)) {
            throw new BusinessException("商品信息不能为空！");
        }
        if (Objects.isNull(goodsInfo.getGoodsId())) {
            throw new BusinessException("商品id不能为空！");
        }
        if (StringUtils.isBlank(goodsInfo.getUnit())) {
            throw new BusinessException("商品单位不能为空！");
        }
        if (Objects.isNull(goodsInfo.getPriceRangeId()) && Objects.equals(source, OrderSourceEnum.PURCHASE.getType())) {
            throw new BusinessException("价格段id不能为空！");
        }
        if (Objects.isNull(goodsInfo.getUnitPrice()) || goodsInfo.getUnitPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException("订单成交单价不能为空且必须大于零！");
        }

        List<UnitInfo> unitInfos = param.getUnitInfo();
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("单位信息不能为空！");
        }
        unitInfos.forEach(e -> {
            if (Objects.isNull(e.getUnitType())) {
                throw new BusinessException("单位类型不能为空！");
            }
            if (Objects.isNull(e.getEntId())) {
                throw new BusinessException("企业id不能为空！");
            }
            if (StringUtils.isBlank(e.getFirmName())) {
                throw new BusinessException("企业名称不能为空！");
            }
            if (Objects.isNull(e.getContactsId())) {
                throw new BusinessException("联系人id不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
        });
        List<AddressInfo> addressInfos = param.getAddressInfo();
        if (CollectionUtils.isEmpty(addressInfos)) {
            throw new BusinessException("地址信息不能为空！");
        }
        addressInfos.forEach(e -> {
            if (StringUtils.isBlank(e.getAddressType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getName())) {
                throw new BusinessException("地址名称不能为空！");
            }
            if (StringUtils.isBlank(e.getType())) {
                throw new BusinessException("地址类型不能为空！");
            }
            if (StringUtils.isBlank(e.getContacts())) {
                throw new BusinessException("联系人姓名不能为空！");
            }
            if (StringUtils.isBlank(e.getPhone())) {
                throw new BusinessException("联系电话不能为空！");
            }
            if (Objects.isNull(e.getCityCode())) {
                throw new BusinessException("所在地区code不能为空！");
            }
            if (StringUtils.isBlank(e.getCityName())) {
                throw new BusinessException("所属区域名称不能为空！");
            }
            if (StringUtils.isBlank(e.getDetailAddress())) {
                throw new BusinessException("详细地址不能为空！");
            }
            if (StringUtils.isBlank(e.getLat())) {
                throw new BusinessException("纬度不能为空！");
            }
            if (StringUtils.isBlank(e.getLng())) {
                throw new BusinessException("经度不能为空！");
            }
        });

    }

    /**
     * @desc: 订单受理
     * @author: yzc
     * @date: 2023-07-14 16:59
     * @Param param:
     * @return: void
     */
    public void acceptanceOrder(AcceptanceOrderParam param) {
        if (param.getPrice().compareTo(param.getUnitPrice().multiply(param.getAmount())) != 0) {
            throw new BusinessException("订单总金额不等于商品单价*订单总量！");
        }
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(OrderStatusEnum.WAIT_ACCEPTED.getCode(), order.getStatus())) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        if (Objects.isNull(goods)) {
            throw new BusinessException("订单商品信息异常！");
        }
        //受理订单总量-原订单总量=订单变化量
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(order.getId());
        List<UnitInfo> unitInfos = BeanUtils.copyToList(units, UnitInfo.class);
        if (CollectionUtils.isEmpty(unitInfos)) {
            throw new BusinessException("订单企业信息异常！");
        }
        BigDecimal amount = param.getAmount().subtract(order.getAmount());
        OrderCheckDTO orderCheck = BeanUtils.copyProperties(param, OrderCheckDTO.class);
        getTopEnt(orderCheck, unitInfos);
        orderCheck.setGoodsId(goods.getGoodsId()).setAmount(amount);
        orderCheck(orderCheck, true);
        //冻结金额
        if (param.getTrading().startsWith("1")) {
            HttpResult freezeResult = paymentDubboService.freezeMoney(orderCheck.getProcureTopEntId(),
                    ChannelEnum.getByTrading(param.getTrading()), orderCheck.getSupplyTopEntId(), param.getPrice(), order.getId());
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, freezeResult.getCode())) {
                throw new BusinessException(freezeResult.getMsg());
            }
        }
        //更新订单信息
        BeanUtils.copyProperties(param, order);
        ContractInfo contractInfo = param.getContractInfo();
        contractCheck(contractInfo);
        String contractStatus = contractInfo.getContractStatus();
        if (Objects.equals(contractStatus, ContractStatusEnum.WAIT_SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.WAIT_SIGNED.getCode());
        } else if (Objects.equals(contractStatus, ContractStatusEnum.SIGNED.getCode())) {
            order.setStatus(OrderStatusEnum.EXECUTING.getCode());
        } else {
            throw new BusinessException("Invalid contract status");
        }
        order.setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()));
        kwoTradeOrderMapper.updateById(order);
        //更新商品价格
        kwoTradeOrderGoodsService.updateUnitPrice(param.getId(), param.getUnitPrice());
        //保存合同信息
        KwoTradeOrderContract tradeOrderContract = BeanUtils.copyProperties(contractInfo, KwoTradeOrderContract.class);
        tradeOrderContract.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo());
        kwoTradeOrderContractService.insert(tradeOrderContract);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //更新库存
        if (amount.compareTo(BigDecimal.ZERO) != 0) {
            HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
            if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                throw new BusinessException(updateResult.getMsg());
            }
        }
        //更新mongodb
        SckwTradeOrder updateParam = BeanUtils.copyProperties(param, SckwTradeOrder.class);
        updateParam.setTOrderId(param.getId())
                .setStatus(order.getStatus())
                .setStartTime(DateUtils.localDateToDateStart(param.getStartTime()))
                .setEndTime(DateUtils.localDateToDateEnd(param.getEndTime()))
                .setPrice(order.getPrice().doubleValue())
                .setAmount(order.getAmount().doubleValue())
                .setUnitPrice(param.getUnitPrice().doubleValue())
                .setContractId(contractInfo.getContractId())
                .setContractNo(contractInfo.getContractNo())
                .setContractName(contractInfo.getContractName())
                .setContractSigningWay(contractInfo.getContractSigningWay())
                .setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateByName(LoginUserHolder.getUserName())
                .setUpdateTime(new Date());
        saveMongoDb(3, updateParam);

    }

    /**
     * @desc: 订单驳回
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param param:
     * @return: void
     */
    public void rejectOrder(RejectOrderParam param) {
        KwoTradeOrder order = getById(param.getId());
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(OrderStatusEnum.WAIT_ACCEPTED.getCode(), order.getStatus())) {
            throw new BusinessException("订单状态不为待受理！");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        order.setStatus(OrderStatusEnum.RETURNED.getCode());
        kwoTradeOrderMapper.updateById(order);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
        kwoTradeOrderTrackService.insert(track);
        //释放商品库存
        KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(order.getId());
        HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), order.getAmount().negate());
        if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
            throw new BusinessException(updateResult.getMsg());
        }
        //mongodb更新订单状态
        SckwTradeOrder updateParam = new SckwTradeOrder();
        updateParam.setTOrderId(order.getId()).setStatus(order.getStatus()).setUpdateBy(LoginUserHolder.getUserId())
                .setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
        saveMongoDb(3, updateParam);
        //发送提醒消息
        List<KwoTradeOrderUnit> units = kwoTradeOrderUnitService.getByOrderId(order.getId());
        rejectOrderSendMsg(units, order);
    }

    /**
     * @desc: 驳回订单发送消息
     * @author: yzc
     * @date: 2023-09-04 16:44
     * @Param units:
     * @Param order:
     * @return: void
     */
    private void rejectOrderSendMsg(List<KwoTradeOrderUnit> units, KwoTradeOrder order) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", order.getTOrderNo());
        Map<String, KwoTradeOrderUnit> unitMap = units.stream().collect
                (Collectors.toMap(KwoTradeOrderUnit::getUnitType, Function.identity()));
        KwoTradeOrderUnit purchase = unitMap.get(OrderUnitTypeEnum.PURCHASE.getType());
        KwoTradeOrderUnit supply = unitMap.get(OrderUnitTypeEnum.SALE.getType());
        //给供应企业联系人发消息
        map.put("firmName", purchase.getFirmName());
        UserInfo supplyUser = new UserInfo();
        supplyUser.setUserId(supply.getContactsId()).setEntId(supply.getTopEntId());
        sendMsg(MessageEnum.ORDER_REJECT_VALET, map, pcValetListUrl, appValetListUrl, List.of(supplyUser));
        //给订单创建人及采购企业联系人发消息
        map.put("firmName", supply.getFirmName());
        List<UserInfo> userInfos = new ArrayList<>();
        UserInfo createUser = new UserInfo();
        createUser.setUserId(order.getCreateBy()).setEntId(order.getEntId());
        userInfos.add(createUser);
        if (!Objects.equals(createUser.getUserId(), purchase.getContactsId())) {
            UserInfo purchaseUser = new UserInfo();
            purchaseUser.setUserId(purchase.getContactsId()).setEntId(purchase.getTopEntId());
            userInfos.add(purchaseUser);
        }
        sendMsg(MessageEnum.ORDER_REJECT_PURCHASE, map, pcPurchaseListUrl, appPurchaseListUrl, userInfos);
    }

    /**
     * @desc: 订单驳回查询
     * @author: yzc
     * @date: 2023-07-14 17:00
     * @Param id:
     * @return: java.lang.String
     */
    public String rejectReason(Long id) {
        KwoTradeOrder order = getById(id);
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (kwoTradeOrderUnitService.entMatch(order.getId(), LoginUserHolder.getEntId(), null)) {
            throw new BusinessException("无订单操作权限！");
        }
        KwoTradeOrderTrack track = kwoTradeOrderTrackService.getByOrderId(id, OrderStatusEnum.RETURNED.getCode());

        return Objects.isNull(track) ? null : track.getRemark();
    }

    /**
     * @desc: 完结订单
     * @author: yzc
     * @date: 2023-07-14 17:01
     * @Param param:
     * @return: void
     */
    public void completeOrder(CompleteOrderParam param) {
        BigDecimal actualAmount = param.getActualAmount();
        Long tOrderId = param.getId();
        KwoTradeOrder order = getById(tOrderId);
        if (Objects.isNull(order)) {
            throw new BusinessException("Order not found");
        }
        if (!Objects.equals(order.getStatus(), OrderStatusEnum.EXECUTING.getCode())) {
            throw new BusinessException("执行中的订单才能完结订单！");
        }
        if (kwoTradeOrderUnitService.entMatch(param.getId(), LoginUserHolder.getEntId(), OrderUnitTypeEnum.SALE.getType())) {
            throw new BusinessException("无订单操作权限！");
        }
        if (transportDubboService.checkLogisticsOrderByTradeOrderId(tOrderId)) {
            throw new CustomPromptException(HttpStatus.COMPLETE_TORDER_FAIL_CODE, "订单存在未完成的物流托运，不可完结！");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, tOrderId);
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            throw new BusinessException("业务繁忙，请稍后再试!");
        }
        try {
            order.setActualAmount(actualAmount).setStatus(OrderStatusEnum.FINISHED.getCode());
            kwoTradeOrderMapper.updateById(order);
            //订单状态记录
            KwoTradeOrderTrack track = new KwoTradeOrderTrack();
            track.setTOrderId(tOrderId).setTOrderNo(order.getTOrderNo()).setRemark(param.getRemark()).setStatus(order.getStatus());
            kwoTradeOrderTrackService.insert(track);
            if (actualAmount.compareTo(order.getAmount()) != 0) {
                KwoTradeOrderGoods goods = kwoTradeOrderGoodsService.getByOrderId(tOrderId);
                if (Objects.isNull(goods)) {
                    throw new BusinessException("商品信息异常！");
                }
                //更新库存
                BigDecimal amount = param.getActualAmount().subtract(order.getAmount());
                HttpResult updateResult = goodsInfoService.updateGoodsAmount(goods.getGoodsId(), amount);
                if (!Objects.equals(HttpStatus.SUCCESS_CODE, updateResult.getCode())) {
                    throw new BusinessException(updateResult.getMsg());
                }
            }
            //更新合同履约量
            KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(tOrderId);
            if (Objects.isNull(contract) || Objects.isNull(contract.getContractId())) {
                throw new BusinessException("订单合同信息异常");
            }
            remoteContractService.updatePerformed(contract.getContractId(), actualAmount);
            //mongodb更新订单状态
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId()).setActualAmount(order.getActualAmount().doubleValue()).setStatus(order.getStatus())
                    .setUpdateBy(LoginUserHolder.getUserId()).setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }

    }


    /**
     * @desc: 批量删除
     * @author: yzc
     * @date: 2023-07-17 20:35
     * @Param param:
     * @return: void
     */
    public void batchDelete(BatchDeleteParam param) {
        List<Long> ids = StringUtils.splitStrToList(param.getIds(), ",", Long.class);
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(KwoTradeOrder::getId, ids).ne(KwoTradeOrder::getStatus, 0).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            throw new BusinessException("删除操作仅针对“已保存”状态的订单");
        }
        //排除草稿状态权限匹配
        List<Long> filterIds = list.stream().filter(e -> !(Objects.equals(e.getStatus(), 0))).map(KwoTradeOrder::getId).toList();
        if (CollectionUtils.isNotEmpty(filterIds) &&
                kwoTradeOrderUnitService.entBatchMatch(filterIds, LoginUserHolder.getEntId(), String.valueOf(param.getOrderType()))) {
            throw new BusinessException("无订单操作权限！");
        }
        LambdaUpdateWrapper<KwoTradeOrder> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(KwoTradeOrder::getDelFlag, Global.YES).in(KwoTradeOrder::getId, ids);
        kwoTradeOrderMapper.update(null, updateWrapper);
        kwoTradeOrderGoodsService.delByOrderIds(ids);
        kwoTradeOrderUnitService.delByOrderIds(ids);
        kwoTradeOrderAddressService.delByOrderIds(ids);
        kwoTradeOrderContractService.delByOrderIds(ids);
        //更新mongodb
        ids.forEach(id -> {
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(id).setDelFlag(Global.YES).setUpdateBy(LoginUserHolder.getUserId())
                    .setUpdateByName(LoginUserHolder.getUserName()).setUpdateTime(new Date());
            saveMongoDb(3, updateParam);
        });

    }

    /**
     * @desc: 根据id获取订单
     * @author: yzc
     * @date: 2023-07-13 17:14
     * @Param id:
     * @return: com.sckw.order.model.KwoTradeOrder
     */
    public KwoTradeOrder getById(Long id) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getId, id).eq(KwoTradeOrder::getDelFlag, Global.NO).last("LIMIT 1");
        return kwoTradeOrderMapper.selectOne(wrapper);
    }

    /**
     * @desc: 根据id更新
     * @author: yzc
     * @date: 2023-07-20 10:24
     * @Param order:
     * @return: void
     */
    public void updateById(KwoTradeOrder order) {
        kwoTradeOrderMapper.updateById(order);
    }


    /**
     * @desc: 根据订单ids获取待签约订单
     * @author: yzc
     * @date: 2023-07-20 14:10
     * @Param tOrderIds:
     * @return: java.util.List<com.sckw.order.model.KwoTradeOrder>
     */
    public List<KwoTradeOrder> getWaitSignByIds(List<Long> tOrderIds) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(KwoTradeOrder::getStatus, OrderStatusEnum.WAIT_SIGNED.getCode())
                .in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getDelFlag, Global.NO);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        return CollectionUtils.emptyIfNull(list);
    }

    /**
     * @desc: 根据订单ids变更待签约订单为执行中
     * @author: yzc
     * @date: 2023-07-20 11:57
     * @Param tOrderIds:
     * @Param updateBy:
     * @return: void
     */
    public void contractCompletedUpdate(List<Long> tOrderIds, Long updateBy) {
        LambdaUpdateWrapper<KwoTradeOrder> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getStatus, OrderStatusEnum.WAIT_SIGNED.getCode())
                .eq(KwoTradeOrder::getDelFlag, Global.NO).set(KwoTradeOrder::getUpdateBy, updateBy)
                .set(KwoTradeOrder::getStatus, OrderStatusEnum.EXECUTING.getCode());
        kwoTradeOrderMapper.update(null, wrapper);
    }

    /**
     * @desc: 获取贸易订单地址下拉列表
     * @author: yzc
     * @date: 2023-08-02 17:28
     * @return: com.sckw.order.model.vo.res.AddressDropListRes
     */
    public AddressDropListRes getAddressDropList() {
        AddressDropListRes res = new AddressDropListRes();
        Long entId = LoginUserHolder.getEntId();
        //一级企业匹配筛选订单id
        List<KwoTradeOrderUnit> unitInfo = kwoTradeOrderUnitService.getByTopEntId(entId);
        if (CollectionUtils.isEmpty(unitInfo)) {
            return res;
        }
        Set<Long> tOrderIds = unitInfo.stream().map(KwoTradeOrderUnit::getTOrderId).collect(Collectors.toSet());
        //订单ids获取地址信息
        List<KwoTradeOrderAddress> addressList = kwoTradeOrderAddressService.getByOrderIds(tOrderIds);
        if (CollectionUtils.isEmpty(addressList)) {
            return res;
        }
        //装卸货地址类型分组获取装卸货cityCodes
        Map<String, List<Integer>> map = addressList.stream().collect(Collectors.
                groupingBy(KwoTradeOrderAddress::getAddressType, Collectors.mapping(KwoTradeOrderAddress::getCityCode, Collectors.toList())));
        //装货地址下拉列表树
        List<AreaTreeFrontResDto> loadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(OrderAddressTypeEnum.LOAD.getType()));
        //卸货地址下拉列表树
        List<AreaTreeFrontResDto> unloadTree = remoteSystemService.queryAreaTreeFrontByCodeList(map.get(OrderAddressTypeEnum.UNLOAD.getType()));
        res.setLoadAddressList(loadTree).setUnloadAddressList(unloadTree);
        return res;
    }

    /**
     * @desc: 根据ids获取进行中的订单
     * @author: yzc
     * @date: 2023-08-17 17:34
     * @Param tOrderIds:
     * @return: java.util.Collection<com.sckw.order.model.KwoTradeOrder>
     */
    public List<KwoTradeOrder> associateEnt(Collection<Long> tOrderIds) {
        LambdaQueryWrapper<KwoTradeOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(KwoTradeOrder::getId, tOrderIds).eq(KwoTradeOrder::getDelFlag, Global.NO)
                .in(KwoTradeOrder::getStatus, 1, 2, 3, 4);
        List<KwoTradeOrder> list = kwoTradeOrderMapper.selectList(wrapper);
        return CollectionUtils.emptyIfNull(list);
    }

    /**
     * @desc: 根据一级企业id查询，企业类型分组，统计非草稿的订单数量
     * @author: yzc
     * @date: 2023-09-11 11:46
     * @Param topEntId:
     * @return: java.util.List<com.sckw.order.api.model.TradeOrderCountStatisticsDTO>
     */
    public List<TradeOrderCountStatisticsDTO> getOrderNumByTopEntId(Long topEntId) {
        return kwoTradeOrderMapper.getOrderNumByTopEntId(topEntId);
    }

    /**
     * @desc: 工作台贸易订单表格统计
     * @author: yzc
     * @date: 2023-09-13 15:46
     * @Param reqDTO:
     * @return: java.util.List<com.sckw.order.model.dto.WbTOrderExcelStsResDTO>
     */
    public List<WbTOrderExcelStsResDTO> workbenchExcel(WbTOrderExcelStsReqDTO reqDTO) {
        List<WbTOrderExcelStsResDTO> list = kwoTradeOrderMapper.workbenchExcel(reqDTO);
        return CollectionUtils.emptyIfNull(list);
    }

}
