package com.sifang.modules.supply.order.service;


import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.sifang.modules.account.dao.TraderAccountDao;
import com.sifang.modules.customer.dao.CustomerEntryDao;
import com.sifang.modules.customer.entity.CustomerEntry;
import com.sifang.modules.flowable.service.ApplicationDetailService;
import com.sifang.modules.flowable.service.ProcessFlowableService;
import com.sifang.modules.flowable.utils.FormUtils;
import com.sifang.modules.flowpath.constant.BondApplyConstant;
import com.sifang.modules.flowpath.service.SettlementAmountAdjustmentApplyService;
import com.sifang.modules.platform.utils.PlantformUtils;
import com.sifang.modules.q7link.entity.WuziOrder;
import com.sifang.modules.q7link.service.CrmSupplyMaterialProjectPriceService;
import com.sifang.modules.q7link.utils.OpenapiTemplate;
import com.sifang.modules.setting.constant.EmpRoleConstants;
import com.sifang.modules.sunshine.SystemSetting.dao.TraderDao;
import com.sifang.modules.sunshine.SystemSetting.entity.CrmTrader;
import com.sifang.modules.sunshine.SystemSetting.utils.BusinessException;
import com.sifang.modules.sunshine.SystemSetting.utils.CustomException;
import com.sifang.modules.sunshine.SystemSetting.utils.Result;
import com.sifang.modules.supply.order.constant.ApplyOrderConstants;
import com.sifang.modules.supply.order.constant.DeliverOrderConstants;
import com.sifang.modules.supply.order.dao.*;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialApply;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrder;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrderDetail;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrderMsg;
import com.sifang.modules.supply.order.request.*;
import com.sifang.modules.supply.order.vo.OrderTbQqVO;
import com.sifang.modules.supply.setting.constant.WarehouseConstants;
import com.sifang.modules.supply.setting.dao.CrmSupplyDeliveryMethodDao;
import com.sifang.modules.supply.setting.dao.CrmSupplyMaterialTypeDao;
import com.sifang.modules.supply.setting.dao.CrmSupplySupplierDao;
import com.sifang.modules.supply.setting.dao.CrmSupplyWarehouseDao;
import com.sifang.modules.supply.setting.entity.CrmSupplyDeliveryMethod;
import com.sifang.modules.supply.setting.entity.CrmSupplyMaterialType;
import com.sifang.modules.supply.setting.entity.CrmSupplySupplier;
import com.sifang.modules.supply.setting.entity.CrmSupplyWarehouse;
import com.sifang.modules.supply.stock.FIFOStockImpl;
import com.sifang.modules.supply.stock.KeepUnit;
import com.sifang.modules.supply.stock.StockUnit;
import com.sifang.modules.supply.stock.dao.MaterialStockDao;
import com.sifang.modules.supply.stock.dao.SupplyMaterialDao;
import com.sifang.modules.supply.stock.entity.MaterialWarehouseStocks;
import com.sifang.modules.supply.stock.entity.SupplyMaterial;
import com.sifang.modules.supply.stock.service.MaterialStockService;
import com.sifang.modules.supply.stock.utils.MaterialUtils;
import com.sifang.modules.supply.warehouse.constant.InventoryOrderConstants;
import com.sifang.modules.supply.warehouse.dao.CrmSupplyMaterialKeepDao;
import com.sifang.modules.supply.warehouse.entity.CrmSupplyMaterialKeep;
import com.sifang.modules.sys.common.UserUtils;
import com.sifang.modules.sys.common.entity.User;
import com.sifang.modules.sys.common.utils.DateUtils;
import com.sifang.modules.sys.common.utils.IdGen;
import com.sifang.modules.sys.common.utils.StringUtil;
import com.sifang.modules.sys.entity.Ascription;
import com.sifang.modules.sys.entity.Operator;
import com.sifang.modules.sys.util.CrmUtils;
import com.sifang.modules.sys.util.LayuiPage;
import com.sifang.modules.sys.util.SqlBuilder;
import org.flowable.engine.TaskService;
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.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author hongzq
 */
@Service
public class DeliverOrderService {

    @Autowired
    MaterialDeliverDao deliverDao;

    @Autowired
    MaterialDeliverDetailDao deliverDetailDao;

    @Autowired
    CrmSupplyWarehouseDao warehouseDao;

    @Autowired
    MaterialStockDao materialStockDao;

    @Autowired
    MaterialDeliverOrderMsgDao deliverOrderMsgDao;

    @Autowired
    MaterialApplyDao materialApplyDao;

    @Autowired
    SupplyExceptionDao supplyExceptionDao;

    @Autowired
    TraderDao traderDao;

    @Autowired
    CrmSupplyDeliveryMethodDao deliveryMethodDao;

    @Autowired
    MaterialApplyMsgDao materialApplyMsgDao;

    @Autowired
    private MaterialStockService materialStockService;

    @Autowired
    private SupplyMaterialDao materialDao;

    @Autowired
    private FIFOStockImpl fifoStock;

    @Autowired
    private ProcessFlowableService flowableService;

    @Autowired
    TaskService taskService;

    @Autowired
    private CrmSupplySupplierDao supplySupplierDao;

    @Autowired
    private SettlementAmountAdjustmentApplyService saaApplyService;

    @Autowired
    TraderAccountDao accountDao;

    @Autowired
    private CrmSupplyMaterialKeepDao materialKeepDao;

    @Autowired
    private CrmSupplyMaterialTypeDao materialTypeDao;
    @Autowired
    private CustomerEntryDao customerEntryDao;
    @Autowired
    private CrmSupplyMaterialProjectPriceService projectPriceService;
    @Autowired
    private ApplicationDetailService applicationDetailService;

    @Resource
    private CrmSupplyMaterialDeliverOrderService crmSupplyMaterialDeliverOrderService;

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

    @Transactional(rollbackFor = Exception.class)
    public void cancelSupplyOrder(String id, String reason, Operator operator) {
        CrmSupplyMaterialDeliverOrder deliverOrder = deliverDao.get(id);
        //仅补库单 且待发货支持撤销
        if (!(DeliverOrderConstants.TYPE_BK.equals(deliverOrder.getType())
                && DeliverOrderConstants.WAIT_DELIVER.equals(deliverOrder.getStatus()))) {
            throw new BusinessException("仅待发货状态的补库单支持撤销");
        }
        deliverOrder.setCancelReason(reason);
        deliverOrder.setStatus(DeliverOrderConstants.CANCELED);
        deliverDao.save(deliverOrder);

        //解冻库存
        List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(id);
        List<AddSupplierOrderDetailReq> reqs = changeList(details);
        unFrozeStockForDeliver(deliverOrder.getOutWarehouseId(), reqs);

        //撤销原因
        deliverOrderMsgDao.saveOptMsg(deliverOrder.getId(), DeliverOrderConstants.OPT_CANCEL, reason, operator);
    }

    @Transactional(rollbackFor = Exception.class)
    public void addSupplyOrder(AddSupplierOrderReq req, Operator operator) {
        if (StrKit.notBlank(req.getId())) {
            editDeliverOrder(req, operator);
        } else {
            addDeliverOrder(req, DeliverOrderConstants.TYPE_BK, null, operator,"");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void editDeliverOrder(AddSupplierOrderReq req, Operator operator) {
        String orderId = req.getId();
        CrmSupplyMaterialDeliverOrder deliverOrder = deliverDao.get(orderId);
        //仅已撤销的可以编辑
        if (!DeliverOrderConstants.CANCELED.equals(deliverOrder.getStatus())) {
            throw new BusinessException("仅已撤销的订单可以编辑");
        }
        setCommonFields(req, deliverOrder);
        deliverOrder.setStatus(DeliverOrderConstants.WAIT_DELIVER);
        deliverDao.save(deliverOrder);

        deliverDetailDao.deleteDetailByOrderId(req.getId());
        saveDetails(req, deliverOrder);

        deliverOrderMsgDao.saveOptMsg(deliverOrder.getId(), DeliverOrderConstants.OPT_EDIT, "", operator);
    }

    /**
     * @param type 0.补库单 1.发货单
     */
    @Transactional(rollbackFor = Exception.class)
    public void addDeliverOrder(AddSupplierOrderReq req, String type, String relateNo, Operator operator,String project_code) {
        CrmSupplyMaterialDeliverOrder deliverOrder = new CrmSupplyMaterialDeliverOrder();
        deliverOrder.setId(IdGen.uuid());
        deliverOrder.setType(type);
        deliverOrder.setNumber(DeliverOrderConstants.TYPE_FH.equals(type) ?
                PlantformUtils.findOrderNumber("FH") : PlantformUtils.findOrderNumber("BK"));
        deliverOrder.setRelateNo(relateNo);
        deliverOrder.setApplyOrderId(req.getApplyOrderId());
        deliverOrder.setProjectCode(project_code);
        setCommonFields(req, deliverOrder);

        deliverOrder.setCreateBy(operator.getUserId());
        deliverOrder.setCreator(operator.getUserName());
        deliverOrder.setCreateTime(new Date());
        deliverOrder.setStatus(DeliverOrderConstants.WAIT_DELIVER);
        deliverDao.save(deliverOrder);

        saveDetails(req, deliverOrder);

        deliverOrderMsgDao.saveOptMsg(deliverOrder.getId(), DeliverOrderConstants.OPT_CREATE, req.getRemarks(), operator);
    }

    @Transactional(rollbackFor = Exception.class)
    public void changeSupply(ChangeSupplyReq req, Operator operator) {
        //只有待发货订单支持改派
        for (String orderId : req.getOrderIds().split(",")) {
            CrmSupplyMaterialDeliverOrder deliverOrder = deliverDao.get(orderId);
            if (!DeliverOrderConstants.WAIT_DELIVER.equals(deliverOrder.getStatus())
                    && !DeliverOrderConstants.CANCELED.equals(deliverOrder.getStatus())) {
                throw new BusinessException("仅未发货订单支持改派");
            }
            if (deliverOrder.getOutWarehouseId().equals(req.getOutWarehouseId())) {
                throw new BusinessException("改派出库仓库不能与原仓库相同");
            }
            //更新关联的物料申请单
            CrmSupplyWarehouse oldWarehouse = warehouseDao.get(deliverOrder.getOutWarehouseId());
            CrmSupplyWarehouse warehouse = warehouseDao.get(req.getOutWarehouseId());
            if (StrKit.notBlank(deliverOrder.getRelateNo())) {
                CrmSupplyMaterialApply apply = materialApplyDao.findByNumber(deliverOrder.getRelateNo());
                apply.setOrderTo(warehouse.getAscriptionId());
                apply.setOrderToName(warehouse.getAscriptionName());
                materialApplyDao.save(apply);
            }
            List<AddSupplierOrderDetailReq> detailReqs = deliverDetailDao.listDetails(deliverOrder.getId());
            //释放原冻结库存
            unFrozeStockForDeliver(deliverOrder.getOutWarehouseId(), detailReqs);
            //冻结库存
            frozeStockForDeliver(req.getOutWarehouseId(), detailReqs);
            //操作记录
            String optMsg = String.format("由供应商：%s，仓库：%s 改派为 供应商：%s，仓库：%s。改派原因：%s", deliverOrder.getDeliverName(), oldWarehouse.getName()
                    , warehouse.getAscriptionName(), warehouse.getName(), req.getReason());
            deliverOrderMsgDao.saveOptMsg(deliverOrder.getId(), DeliverOrderConstants.OPT_CHANGE, optMsg, operator);

            deliverOrder.setOutWarehouseId(req.getOutWarehouseId());
            deliverOrder.setDeliverId(warehouse.getAscriptionId());
            deliverOrder.setDeliverName(warehouse.getAscriptionName());
            deliverDao.save(deliverOrder);

            //例外统计
            Ascription ascription = new Ascription(oldWarehouse.getAscriptionId(), oldWarehouse.getAscriptionName());
            supplyExceptionDao.saveException(deliverOrder.getNumber(), "3", req.getReason(), "1", deliverOrder.getPlaceTime(), ascription, operator);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteSupplyOrder(String orderIds, Operator operator) {
        for (String orderId : orderIds.split(",")) {
            CrmSupplyMaterialDeliverOrder deliverOrder = deliverDao.get(orderId);
            if (!DeliverOrderConstants.CANCELED.equals(deliverOrder.getStatus())) {
                throw new BusinessException("仅已撤销的订单支持删除");
            }
            deliverOrder.setStatus(DeliverOrderConstants.DELETED);
            deliverDao.save(deliverOrder);

            //操作记录
            deliverOrderMsgDao.saveOptMsg(deliverOrder.getId(), DeliverOrderConstants.OPT_DELETE, "", operator);
        }
    }

    //发货单拆单
    @Transactional(rollbackFor = Exception.class)
    public void splitDeliverOrder(AllocationReq allocationReq,TraderOrderReq req, Operator operator) {
        //本次分配的
        allocation(allocationReq);
        //拆单的
        String deliverOrderId = req.getOrderId();
        CrmSupplyMaterialDeliverOrder deliverOrder = deliverDao.get(deliverOrderId);
        //只有采购分配可以操作拆单
//        if (!DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION.equals(deliverOrder.getStatus())) {
//            throw new BusinessException("订单状态已发生变化，请刷新后再试");
//        }
        if(StringUtil.isBlank(deliverOrder.getProvince())){
            CrmSupplyWarehouse warehouse = warehouseDao.get(deliverOrder.getInWarehouseId());
            deliverOrder.setProvince(warehouse.getProvince());
            deliverOrder.setCity(warehouse.getCity());
            deliverOrder.setArea(warehouse.getArea());
            deliverOrder.setAddress(warehouse.getAddress());
        }

        Map<String, TraderOrderDetailReq> detailReqMap = getTraderOrderDetailReqMap(req.getDetails());
        List<CrmSupplyMaterialDeliverOrderDetail> deliverDetails = deliverDetailDao.listDetailByOrderId(deliverOrderId);

        CrmSupplyMaterialDeliverOrder newOrder = null;
        String number0 = deliverOrder.getNumber();
        String  number = number0;
        if(number0.contains("-")){
            number = number0.substring(0, number0.indexOf("-"));
        }
        Integer maxVersion = deliverDao.findMaxVersion(number);
        int version = maxVersion + 1;
        String newNumber =  number +"-"+version;
        if (version<10){
            newNumber = number+"-0"+version;
        }
        newOrder = createNewSplitOrder(deliverOrder, newNumber, operator);
        newOrder.setVersion(version);

//        CrmSupplyMaterialDeliverOrder oldOrder = createNewSplitOrder(deliverOrder, "-01", operator);
//        CrmSupplyMaterialDeliverOrder newOrder = createNewSplitOrder(deliverOrder, "-02", operator);

        //原订单剩余
//        List<CrmSupplyMaterialDeliverOrderDetail> oldOrderDetails = new ArrayList<>();
        //新订单
        List<CrmSupplyMaterialDeliverOrderDetail> newOrderDetails = new ArrayList<>();
        for (CrmSupplyMaterialDeliverOrderDetail deliverDetail : deliverDetails) {
            TraderOrderDetailReq detailReq = detailReqMap.get(deliverDetail.getId());
            if (detailReq != null){
                //新订单
                addDetails(newOrderDetails, deliverDetail.getMaterialId(),
                        detailReq.getAmount(),detailReq.getAmount(), deliverDetail.getMaterialSpec(), deliverDetail.getMaterialType(), deliverDetail.getSalesPrice(), deliverDetail.getPurchasePrice(), newOrder.getId());
            }

//            if (detailReq != null && detailReq.getAmount().compareTo(BigDecimal.ZERO) > 0) {
//                if (deliverDetail.getOutAmount().compareTo(detailReq.getAmount()) < 0) {
//                    throw new BusinessException("拆单数量不能超过实发数量");
//                }
//                if (deliverDetail.getOutAmount().subtract(detailReq.getAmount()).compareTo(BigDecimal.ZERO) > 0) {
//                    addDetails(oldOrderDetails, deliverDetail.getMaterialId(),
//                            deliverDetail.getOutAmount().subtract(detailReq.getAmount()),deliverDetail.getOutAmount().subtract(detailReq.getAmount()), deliverDetail.getMaterialSpec(), deliverDetail.getMaterialType(), deliverDetail.getSalesPrice(), deliverDetail.getPurchasePrice(), oldOrder.getId());
//                }
//                //新订单
//                addDetails(newOrderDetails, deliverDetail.getMaterialId(),
//                        detailReq.getAmount(),detailReq.getAmount(), deliverDetail.getMaterialSpec(), deliverDetail.getMaterialType(), deliverDetail.getSalesPrice(), deliverDetail.getPurchasePrice(), newOrder.getId());
//            } else {
//                addDetails(oldOrderDetails, deliverDetail.getMaterialId(),
//                        deliverDetail.getOutAmount(),deliverDetail.getApplyAmount(), deliverDetail.getMaterialSpec(), deliverDetail.getMaterialType(), deliverDetail.getSalesPrice(), deliverDetail.getPurchasePrice(), oldOrder.getId());
//            }
        }
//        if (newOrderDetails.isEmpty() || oldOrderDetails.isEmpty()) {
//            throw new BusinessException("无可拆订单");
//        }
          if (newOrderDetails.isEmpty()) {
            throw new BusinessException("无可拆订单");
        }
//        deliverDetailDao.save(oldOrderDetails);
        deliverDetailDao.save(newOrderDetails);

        //维护物料类型和物料数量
//        oldOrder.setMaterialTypeAmount(new BigDecimal(oldOrderDetails.size()));
//        oldOrder.setTotalApplyAmount(sumTotalAmount(oldOrderDetails));
        BigDecimal predictAmount=BigDecimal.ZERO; //预估授信额度
        for (CrmSupplyMaterialDeliverOrderDetail newOrderDetail : newOrderDetails) {
            predictAmount=predictAmount.add(newOrderDetail.getSalesPrice().multiply(newOrderDetail.getOutAmount()));
        }
        newOrder.setPredictAmount(predictAmount);
        newOrder.setMaterialTypeAmount(new BigDecimal(newOrderDetails.size()));
        newOrder.setTotalApplyAmount(sumTotalAmount(newOrderDetails));
//        deliverDao.save(oldOrder);
        deliverDao.save(newOrder);

//        deliverOrder.setStatus(DeliverOrderConstants.STATUS_SPLIT2);
//        deliverOrder.setRelateNo(StringUtil.appendMultiString(deliverOrder.getRelateNo(), oldOrder.getNumber(), newOrder.getNumber()));
        deliverDao.save(deliverOrder);
        //删除发货数量为0的物料
        for (CrmSupplyMaterialDeliverOrderDetail deliverDetail : deliverDetails) {
            if (deliverDetail.getOutAmount().compareTo(BigDecimal.ZERO) == 0){
                deliverDetailDao.deleteById(deliverDetail.getId());
            }
        }
        //拆单
        deliverOrderMsgDao.saveOptMsg(req.getOrderId(), DeliverOrderConstants.OPT_SPLIT, "", operator);
    }

    private BigDecimal sumTotalAmount(List<CrmSupplyMaterialDeliverOrderDetail> details) {
        BigDecimal total = BigDecimal.ZERO;
        for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
            total = total.add(detail.getApplyAmount());
        }
        return total;
    }

    @Transactional(rollbackFor = Exception.class)
    public void doDeliver(DeliverReq req, Operator operator, String type) {
        User user = UserUtils.getUser();
        CrmSupplyDeliveryMethod deliveryMethod = deliveryMethodDao.get(req.getDeliverMethodId());
        TraderOrderReq orderReq = req.getMaterialInfo();
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(orderReq.getOrderId());
        order.setDeliverTime(new Date());
        if ("1".equals(req.getType())) {
            if ("0".equals(deliveryMethod.getType()) && StrKit.isBlank(req.getExpressNo())) {
                throw new BusinessException("物流单号不能为空");
            }

            if (!StringUtil.endsWithAny(order.getStatus(), DeliverOrderConstants.STATUS_WAIT_DELIVER, DeliverOrderConstants.STATUS_DELIVER_REJECT)) {
                throw new BusinessException("只有待发货和仓库打回的订单可以操作发货");
            }
            if(!"0".equals(order.getSendStatus())){
                throw new BusinessException("只有待发货的订单可以操作发货");
            }
            // 释放库存标记 发货时 发货仓与分配时发货仓一样，则需要解冻
            boolean unfreezeFlag = false;
            //发货总数不能为零
            List<TraderOrderDetailReq> detailReqs = orderReq.getDetails();
            // 判断是否入库代理商
            CrmSupplyWarehouse inWarehouse = warehouseDao.get(order.getInWarehouseId());
            boolean flag = InventoryOrderConstants.DISTRIBUTOR.equals(inWarehouse.getType());
            //更新实发数量、释放多余的库存
            BigDecimal totalAmount = BigDecimal.ZERO;
            BigDecimal adjustAmount = BigDecimal.ZERO;
            BigDecimal totalAccountAmount = BigDecimal.ZERO;//代理商授信额
            if ("1".equals(user.getUserType()) || "4".equals(user.getUserType())) {
                // 平台端发货，需要处理库存信息
                List<CrmSupplyMaterialDeliverOrderDetail> orderDetailist =   deliverDetailDao.listDetailByOrderId(order.getId());

                // 释放库存标记 发货时 发货仓与分配时发货仓一样，则需要解冻


                for (CrmSupplyMaterialDeliverOrderDetail orderDetail : orderDetailist) {
                    SupplyMaterial material = materialDao.get(orderDetail.getMaterialId());
                    //发货数量不能超过冻结待出库数量、不能超过实物库存
                    MaterialWarehouseStocks stocks = materialStockDao.findByWarehouse(orderDetail.getMaterialId(), order.getOutWarehouseId());
                    if (orderDetail.getOutAmount().compareTo(stocks.getFrozeOutNum()) > 0) {
                        throw new BusinessException("发货数量不能超过冻结待出库数量");
                    }
                    if (orderDetail.getOutAmount().compareTo(stocks.getRealNum()) > 0) {
                        throw new BusinessException("发货数量不能超过实际库存");
                    }
                    // 按库存批次先进先出出库
                    StockUnit stockUnit = new StockUnit(orderDetail.getMaterialId(), order.getOutWarehouseId());
//                    String keepId = IdGen.uuid();
                    KeepUnit keepUnit = new KeepUnit(operator.getUserId(), operator.getUserName(), "2", "4", order.getId(),
                            order.getNumber(), order.getDeliverRemark(), orderDetail.getMaterialId(), material.getCode(),
                            orderDetail.getMaterialType(), material.getRemarks(), orderDetail.getPurchasePrice(), orderDetail.getSalesPrice(),
                            orderDetail.getOutAmount(), order.getOutWarehouseId(), "",material.getUnitName());
                    fifoStock.deliverForBatch(stockUnit, keepUnit, orderDetail.getOutAmount(),deliveryMethod.getName());

                    //  stocks.setWarning(stocks.getWarning().subtract(orderDetail.getOutAmount()));
                    stocks.setRealNum(stocks.getRealNum().subtract(orderDetail.getOutAmount()));
                    // 解冻库存
                    stocks.setFrozeOutNum(stocks.getFrozeOutNum().subtract(orderDetail.getOutAmount()));
                    orderDetail.setMaterialCode(material.getCode());
                    orderDetail.setUnitCode(material.getUnitCode());
                    materialStockDao.save(stocks);
                    deliverDetailDao.save(orderDetail);
                    //计算调整金额
                    if ("1".equals(material.getMaterialAttribute())) {
                        adjustAmount = adjustAmount.add(orderDetail.getOutAmount().multiply(orderDetail.getSalesPrice()));
                    }
                    totalAmount = totalAmount.add(orderDetail.getOutAmount());

                    if(flag && orderDetail.getOutAmount()!=null && orderDetail.getSalesPrice()!=null){
                        totalAccountAmount=totalAccountAmount.add(orderDetail.getOutAmount().multiply(orderDetail.getSalesPrice()));
                    }
                }

                //结算账户生成[自选产品退货] 记录
                if (adjustAmount.compareTo(BigDecimal.ZERO) > 0 && StringUtil.isNotBlank(order.getTraderId())) {
                    saaApplyService.saveSettlementAmountApplyFromDeliver(order,adjustAmount);
                }
                if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
                    throw new BusinessException("发货总数不能为0");
                }
                order.setTotalDeliverAmount(totalAmount);
                //待入库
                order.setStatus(DeliverOrderConstants.STATUS_WAIT_SIGN_IN);
                // order.setSendStatus("1");//待审核
            } else {

                // 供应商端发货，不需要处理库存信息
                Boolean fg = false;
                //供应商直接发货，在供应链仓库生成同时间的出入库记录
                logger.info(">>>>>>>>>>>doDeliver  orderId:{},pattern:{},type:{}", order.getId(), order.getPattern(), order.getType());
                if ("2".equals(order.getPattern())) {  // 供应商直发（订单分配由供应商直发给代理商的订单）
                    fg = true;
                }
                List<CrmSupplyMaterialDeliverOrderDetail> details = new ArrayList<>();
                for (TraderOrderDetailReq detailReq : detailReqs) {
                    CrmSupplyMaterialDeliverOrderDetail orderDetail = deliverDetailDao.get(detailReq.getDetailId());
                    totalAmount = totalAmount.add(orderDetail.getOutAmount());
                    SupplyMaterial material = materialDao.get(orderDetail.getMaterialId());
                    //计算调整金额
                    if ("1".equals(material.getMaterialAttribute())) {
                        adjustAmount = adjustAmount.add(orderDetail.getOutAmount().multiply(orderDetail.getSalesPrice()));
                    }
                    if(flag && orderDetail.getOutAmount()!=null && orderDetail.getSalesPrice()!=null){
                        totalAccountAmount=totalAccountAmount.add(orderDetail.getOutAmount().multiply(orderDetail.getSalesPrice()));
                    }
                    if (fg) {
                        CrmSupplyMaterialType materialType = materialTypeDao.get(material.getMaterialTypeId());
                        //saveMaterialKeep(material, materialType, user, order, orderDetail.getOutAmount(), orderDetail.getPurchasePrice(),orderDetail.getSalesPrice(),"1", "2");  //生成一条入库单
                        saveMaterialKeep(material, materialType, user, order, orderDetail.getOutAmount(), orderDetail.getPurchasePrice(),orderDetail.getSalesPrice(),"2", "4");  //生成一条出库单
                    }
                    orderDetail.setUnitCode(material.getUnitCode());
                    orderDetail.setMaterialCode(material.getCode());
                    details.add(orderDetail);
                }

                //结算账户生成[自选产品退货] 记录
                if (adjustAmount.compareTo(BigDecimal.ZERO) > 0 && StringUtil.isNotBlank(order.getTraderId())) {
                    saaApplyService.saveSettlementAmountApplyFromDeliver(order, adjustAmount);
                }
                if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
                    throw new BusinessException("发货总数不能为0");
                }
                order.setTotalDeliverAmount(totalAmount);
                //待入库
                order.setStatus(DeliverOrderConstants.STATUS_WAIT_SIGN_IN);

            }
            order.setOutWarehouseId(req.getOutWarehouseId());
            order.setPredictAmount(totalAccountAmount);
//            //判断物料总额和 代理商授信额
//            if (flag) {
//                CrmTraderAccount account = accountDao.findByTraderId(order.getTraderId());
//                if (account == null) {
//                    throw new BusinessException("请新增代理商的可授信额度!");
//                }
//                if (account.getBasicQuotaAmountBalance().compareTo(totalAccountAmount) < 0) {
//                    throw new BusinessException("代理商标准授信额不足，不能通过!");
//                }
//                // 修改代理商账户
//                if (totalAccountAmount.compareTo(BigDecimal.ZERO) > 0) {
//                    account.setBasicQuotaAmountBalance(account.getBasicQuotaAmountBalance().subtract(totalAccountAmount));
//                    account.setMaxQuotaAmountBalance(account.getMaxQuotaAmountBalance().subtract(totalAccountAmount));
//                    accountDao.save(account);
//                }
//            }
        }
        order.setDeliveryVoucher(req.getDeliveryVoucher());
        //更新订单状态
        order.setDeliverMethodId(req.getDeliverMethodId());
        order.setDeliverMethodName(deliveryMethod != null ? deliveryMethod.getName() : "");
        if ("0".equals(deliveryMethod.getType())) {
            order.setExpressNo(req.getExpressNo());
        } else {
            order.setDeliverDriver(req.getDeliverDriver());
            order.setDeliverMobile(req.getDeliverMobile());
            order.setDeliverCarNum(req.getDeliverCarNum());
        }
        order.setDeliverRemark(req.getDeliverRemark());

        deliverDao.save(order);
        //操作记录
        if ("1".equals(type)) {
            //发货
            deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.OPT_FH, "", operator);

            //更新电站发货时间
         /*   if (customerEntryDao.findEntryByDeliverId(order.getId()) > 0) {
                StringBuilder sb = new StringBuilder();
                sb.append("update crm_customer_entry set deliver_order_time=:deliverOrderTime ");
                sb.append(" where deliver_id =:deliverId ");
                SQLQuery sqlQuery = customerEntryDao.getSession().createSQLQuery(sb.toString());
                sqlQuery.setParameter("deliverOrderTime",order.getDeliverTime());
                sqlQuery.setParameter("deliverId",order.getId());
                sqlQuery.executeUpdate();
            }*/
        } else {
            deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.OPT_EDIT, "", operator);
        }
        // 当前发货 不支持暂存 所以不判断当前操作
        insertOutStockQq(order.getId());
    }

    /**
     * 订单出库信息同步到企企
     * @param orderId
     */
    private void insertOutStockQq (String orderId){
        OrderTbQqVO orderTbQq = crmSupplyMaterialDeliverOrderService.tbDate(orderId);
        String querySql=" select qq_id from crm_supply_material_deliver_order_qq where status='0' and order_id=? limit 1";
        Record rd = Db.findFirst(querySql, orderTbQq.getId());
        String qqId = (rd != null ? rd.getStr("qq_id") : "");
        WuziOrder wuziOrder = crmSupplyMaterialDeliverOrderService.getWuziOrder(qqId);
        //保存已生成的领用出库单记录
        String result = OpenapiTemplate.addOutStorehouseToQQ(orderTbQq, qqId, wuziOrder);
        Map map= JSONObject.parseObject(result);
        if(map != null && map.get("code") != null && map.get("id") != null){
            String pickingIssueCode = String.valueOf(map.get("code"));
            String pickingIssueId = String.valueOf(map.get("id"));
            boolean insertResult = crmSupplyMaterialDeliverOrderService.savePickingIssue(qqId, pickingIssueId, pickingIssueCode);
            logger.info("------->>>>>>推送领用出库单返回的结果:{}", insertResult);
        }
    }

    private void saveMaterialKeep(SupplyMaterial material, CrmSupplyMaterialType materialType, User user, CrmSupplyMaterialDeliverOrder order, BigDecimal amount,BigDecimal cost_price,BigDecimal bd_sale_price, String type, String source) {
        CrmSupplyMaterialKeep keep = new CrmSupplyMaterialKeep();
        keep.setId(IdGen.uuid());
        keep.setBelongingType("1");
        keep.setMaterialId(material.getId());
        keep.setMaterialCode(material.getCode());
        keep.setMaterialUnit(material.getUnitName());
        keep.setMaterialRemarks(material.getRemarks());
        keep.setMaterialType(materialType.getName());
        keep.setType(type);
        keep.setAmount(amount);
        keep.setCurBgNum(BigDecimal.ZERO);
        keep.setWarehouseId("");
        keep.setWarehouseName("");
        keep.setCostPrice(cost_price);
        keep.setBdSalePrice(bd_sale_price);
        keep.setAscriptionName("");
        keep.setAscriptionId("");
        keep.setCreateTime(new Date());
        keep.setCreateBy(user.getId());
        keep.setCreator(CrmUtils.getUserXM(user));
        keep.setSourceCode(order.getNumber());
        keep.setSourceId(order.getId());
        keep.setSource(source);
        keep.setRemarks(order.getRemarks());
        materialKeepDao.save(keep);
    }

    private Map<String, TraderOrderDetailReq> getTraderOrderDetailReqMap(List<TraderOrderDetailReq> detailReq) {
        Map<String, TraderOrderDetailReq> map = new HashMap<>();
        for (TraderOrderDetailReq req : detailReq) {
            map.put(req.getDetailId(), req);
        }
        return map;
    }

    private void addDetails(List<CrmSupplyMaterialDeliverOrderDetail> list, String materialId, BigDecimal outAmount, BigDecimal applyAmount, String materialSpec, String materialType, BigDecimal salesPrice, BigDecimal purchasePrice, String applyId) {
        boolean exist = false;
        for (CrmSupplyMaterialDeliverOrderDetail detail : list) {
            if (detail.getMaterialId().equals(materialId)) {
                exist = true;
                detail.setApplyAmount(detail.getApplyAmount().add(applyAmount));
                detail.setOutAmount(detail.getOutAmount().add(outAmount));
                break;
            }
        }
        if (!exist) {
            CrmSupplyMaterialDeliverOrderDetail deliverDetail = new CrmSupplyMaterialDeliverOrderDetail();
            deliverDetail.setMainId(applyId);
            deliverDetail.setMaterialId(materialId);
            deliverDetail.setApplyAmount(applyAmount);
            deliverDetail.setOutAmount(outAmount);
            deliverDetail.setInAmount(BigDecimal.ZERO);
            deliverDetail.setSort(list.size() + 1);
            deliverDetail.setMaterialSpec(materialSpec);
            deliverDetail.setMaterialType(materialType);
            deliverDetail.setSalesPrice(salesPrice);
            deliverDetail.setPurchasePrice(purchasePrice);
            deliverDetail.setStatus("0");
            list.add(deliverDetail);
        }
    }

    private CrmSupplyMaterialDeliverOrder createNewSplitOrder(CrmSupplyMaterialDeliverOrder order, String suffix, Operator operator) {
        CrmSupplyMaterialDeliverOrder oldOrder = new CrmSupplyMaterialDeliverOrder();
        oldOrder.setId(IdGen.uuid());
        oldOrder.setNumber(suffix);
        oldOrder.setType(order.getType());
        oldOrder.setPattern(order.getPattern());
        oldOrder.setProjectCode(order.getProjectCode());
        oldOrder.setTraderId(order.getTraderId());
        oldOrder.setApplyOrderId(order.getApplyOrderId());
        oldOrder.setRelateNo(order.getRelateNo());
        oldOrder.setInWarehouseId(order.getInWarehouseId());
        oldOrder.setOutWarehouseId(order.getOutWarehouseId());
        oldOrder.setDeliverId(order.getDeliverId());
        oldOrder.setDeliverName(order.getDeliverName());
        oldOrder.setRemarks(order.getRemarks());
        oldOrder.setPlaceBy(order.getPlaceBy());
        oldOrder.setPlaceName(order.getPlaceName());
        oldOrder.setPlaceTime(order.getPlaceTime());
        oldOrder.setProvince(order.getProvince());
        oldOrder.setCity(order.getCity());
        oldOrder.setArea(order.getArea());
        oldOrder.setAddress(order.getAddress());
        oldOrder.setAuditTime(order.getAuditTime());
        oldOrder.setCancelReason(order.getCancelReason());
        oldOrder.setWarehouseFailReason(order.getWarehouseFailReason());
        oldOrder.setAuditRemark(order.getAuditRemark());
        oldOrder.setPlaceName(order.getPlaceName());
        oldOrder.setPlaceBy(order.getPlaceBy());
        oldOrder.setPlaceTime(order.getPlaceTime());
        oldOrder.setOrderExamineStatus(order.getOrderExamineStatus());
        oldOrder.setProcessInstanceId(order.getProcessInstanceId());
        oldOrder.setPurchaseOrderExamineStatus(order.getPurchaseOrderExamineStatus());
        oldOrder.setPurchaseProcessInstanceId(order.getProcessInstanceId());
        oldOrder.setTaskName(order.getTaskName());
        oldOrder.setTaskId(order.getTaskId());
        oldOrder.setProcessDefId(order.getProcessDefId());

        oldOrder.setCreateBy(order.getCreateBy());
        oldOrder.setCreator(order.getCreator());
        oldOrder.setCreateTime(new Date());
        oldOrder.setTotalDeliverAmount(BigDecimal.ZERO);
        oldOrder.setOperateUserIds(order.getOperateUserIds());
        oldOrder.setInsuranceFiles(order.getInsuranceFiles());
        oldOrder.setSafetyFiles(order.getSafetyFiles());
        oldOrder.setQqProjectCode(order.getQqProjectCode());
        //待发货
        oldOrder.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION);
        deliverDao.save(oldOrder);

        // 保存操作记录
        deliverOrderMsgDao.saveOptMsg(oldOrder.getId(), DeliverOrderConstants.OPT_SPLIT, "由拆单生成，关联单号：" + order.getNumber(), operator);
        return oldOrder;
    }

    private void saveDetails(AddSupplierOrderReq req, CrmSupplyMaterialDeliverOrder order) {
        List<AddSupplierOrderDetailReq> detailReqs = req.getDetails();
        List<CrmSupplyMaterialDeliverOrderDetail> details = new ArrayList<>();
        int i = 0;
        Set<String> materialSet = new HashSet<>();
        for (AddSupplierOrderDetailReq detailReq : detailReqs) {
            if (detailReq.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
                throw new BusinessException("申请数量需大于0");
            }
            if (!materialSet.add(detailReq.getMaterialId())) {
                throw new BusinessException("申请物料不能重复");
            }
            CrmSupplyMaterialDeliverOrderDetail orderDetail = new CrmSupplyMaterialDeliverOrderDetail();
            orderDetail.setMainId(order.getId());
            orderDetail.setMaterialId(detailReq.getMaterialId());
            orderDetail.setApplyAmount(detailReq.getAmount());
            orderDetail.setOutAmount(detailReq.getAmount());
            orderDetail.setInAmount(BigDecimal.ZERO);
            orderDetail.setSort(i++);
            details.add(orderDetail);
        }
        deliverDetailDao.save(details);
        //冻结库存
        List<AddSupplierOrderDetailReq> reqs = changeList(details);
        frozeStockForDeliver(order.getOutWarehouseId(), reqs);
    }

    private List<AddSupplierOrderDetailReq> changeList(List<CrmSupplyMaterialDeliverOrderDetail> details) {
        List<AddSupplierOrderDetailReq> reqs = new ArrayList<>();
        for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
            AddSupplierOrderDetailReq detailReq = new AddSupplierOrderDetailReq();
            detailReq.setMaterialId(detail.getMaterialId());
            detailReq.setAmount(detail.getApplyAmount());
            reqs.add(detailReq);
        }
        return reqs;
    }

    private void setCommonFields(AddSupplierOrderReq req, CrmSupplyMaterialDeliverOrder deliverOrder) {
        CrmSupplyWarehouse outWarehouse = warehouseDao.get(req.getOutWarehouseId());
        CrmSupplyWarehouse inWarehouse = warehouseDao.get(req.getInWarehouseId());
        deliverOrder.setOutWarehouseId(req.getOutWarehouseId());
        deliverOrder.setInWarehouseId(req.getInWarehouseId());
        deliverOrder.setRemarks(req.getRemarks());
        if ("1".equals(outWarehouse.getType())) {
            deliverOrder.setDeliverId("a");
            deliverOrder.setDeliverName("供应链");
        } else {
            deliverOrder.setDeliverId(outWarehouse.getAscriptionId());
            deliverOrder.setDeliverName(outWarehouse.getAscriptionName());
        }
        if ("1".equals(inWarehouse.getType())) {
            deliverOrder.setPlaceBy("a");
            deliverOrder.setPlaceName("供应链");
        } else {
            deliverOrder.setPlaceBy(inWarehouse.getAscriptionId());
            deliverOrder.setPlaceName(inWarehouse.getAscriptionName());
        }
        deliverOrder.setPlaceTime(new Date());

        BigDecimal totalAmount = BigDecimal.ZERO;
        for (AddSupplierOrderDetailReq detailReq : req.getDetails()) {
            totalAmount = totalAmount.add(detailReq.getAmount());
        }
        deliverOrder.setMaterialTypeAmount(new BigDecimal(req.getDetails().size()));
        deliverOrder.setTotalApplyAmount(totalAmount);
        deliverOrder.setTotalDeliverAmount(BigDecimal.ZERO);
    }

    @Transactional(rollbackFor = Exception.class)
    public void frozeStockForDeliver(String outWarehouseId, List<AddSupplierOrderDetailReq> detailReqs) {
        for (AddSupplierOrderDetailReq detailReq : detailReqs) {
            materialStockDao.frozeStock(detailReq.getMaterialId(), outWarehouseId, detailReq.getAmount());
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void unFrozeStockForDeliver(String outWarehouseId, List<AddSupplierOrderDetailReq> detailReqs) {
        for (AddSupplierOrderDetailReq detailReq : detailReqs) {
            materialStockDao.unFrozeStock(detailReq.getMaterialId(), outWarehouseId, detailReq.getAmount());
        }
    }

    public void deliverOrderListPage(LayuiPage<Record> page, Map<String, String> map) {
        page.setData(deliverDao.deliverOrderList(page, map));
        page.setCount(deliverDao.countDeliverOrderList(map));
    }

    public void allOrderListPage(LayuiPage<Record> page, Map<String, String> map) {
        page.setData(deliverDao.allOrderList(page, map));
        page.setCount(deliverDao.countAllOrderList(map));
    }

    public Record getOrderDetail(String orderId) {
        Map<String, String> map = new HashMap<>();
        map.put("applyOrderId", orderId);
        List<Record> orders = deliverDao.allOrderList(null, map);
        if (orders.isEmpty()) {
            return null;
        }
        return orders.get(0);
    }

    public CrmSupplyMaterialDeliverOrder findByOrderId(String orderId) {
        return deliverDao.get(orderId);
    }

    public List<Record> findDetailsByOrderId(String orderId) {
        return deliverDetailDao.findDetailsByOrderId(orderId);
    }

    public Record findOrderById(String id) {
        Map<String, String> map = new HashMap<>();
        map.put("id", id);
        List<Record> orderList = deliverDao.deliverOrderList(null, map);
        return orderList.isEmpty() ? null : orderList.get(0);
    }

    public List<CrmSupplyMaterialDeliverOrderMsg> listMsgByOrderId(String id) {
        return deliverOrderMsgDao.listMsgByOrderId(id);
    }

    public void deleteOrder(String orderId) throws CustomException {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(orderId);

        if(DeliverOrderConstants.COMPLETED.equals(order.getStatus())|| DeliverOrderConstants.EIGTH.equals(order.getStatus())){
            throw new CustomException("已完成入库不可删除","501");
        }
        List<Record> list = deliverDetailDao.findDetailsByOrderId(orderId);
        String type="1";
        if(!"a".equals(order.getDeliverId())){
            type="2";
        }
        String warehouse_id = order.getOutWarehouseId();
        for(Record record:list){
            String material_id = record.getStr("material_id");
            BigDecimal amou = record.getBigDecimal("apply_amount");
            int count =  Db.update("UPDATE crm_supply_material_warehouse_stocks SET warning = warning+? , froze_out_num = froze_out_num -? WHERE material_id = ? AND warehouse_id=? AND type=?",amou,amou,material_id,warehouse_id,type);
            if(count<1){
                logger.info("修改库存信息失败：orderId :{} ,warehouse_id：{} ，material_id：{} , amou{}",orderId,warehouse_id,material_id,amou);
            }
        }
        order.setStatus(DeliverOrderConstants.DELETED);
        deliverDao.save(order);
        if(DeliverOrderConstants.TYPE_FH.equals(order.getType())){
            CrmSupplyMaterialApply applyOrder = materialApplyDao.get(order.getApplyOrderId());
            applyOrder.setStatus(ApplyOrderConstants.DELETED);
            materialApplyDao.save(applyOrder);
            //操作记录
            materialApplyMsgDao.saveOptMsg(applyOrder.getId(), ApplyOrderConstants.OPT_DELETED, "", Operator.of(UserUtils.getUser()));
        }

    }

    /**
     * 分配前校验
     */
    public void checkBeforeAllocation(AllocationReq req) {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(req.getId());
        if (!StrKit.notNull(order)) {
            throw new BusinessException("订单不存在");
        }
        if(!StringUtil.equalsAny(order.getStatus(),DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION,DeliverOrderConstants.STATUS_DELIVER_REJECT,DeliverOrderConstants.STATUS_SPLIT)){
            throw new BusinessException("订单状态已变更");
        }
        if (EmpRoleConstants.SUPPLY_CHAIN.equals(req.getDeliverId())) {
            CrmSupplyWarehouse warehouse = warehouseDao.get(req.getOutWarehouseId());
            if (!StrKit.notNull(warehouse)) {
                throw new BusinessException("发货仓库不存在");
            }
            if (!WarehouseConstants.NORMAL.equals(warehouse.getStatus())) {
                throw new BusinessException("发货仓库状态异常");
            }
            if (!EmpRoleConstants.SUPPLY_CHAIN.equals(warehouse.getAscriptionId())) {
                throw new BusinessException("发货仓库非供应链归属");
            }
        } else {
            CrmSupplySupplier supplier = supplySupplierDao.get(req.getDeliverId());
            if (!StrKit.notNull(supplier)) {
                throw new BusinessException("供应商不存在");
            }
            if (!"0".equals(supplier.getStatus())) {
                throw new BusinessException("供应商状态异常");
            }
        }
    }

    /**
     * 分配
     */
    @Transactional(rollbackFor = Exception.class)
    public void allocation(AllocationReq req) {
        checkBeforeAllocation(req);
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(req.getId());
        Date now = new Date();
        order.setAllocationRemark(req.getAllocationRemark());
        order.setAllocationTime(now);
        order.setDeliverId(req.getDeliverId());
        if ("a".equals(req.getDeliverId())) {
            order.setDeliverName("平台发货");
        } else {
            order.setDeliverName(MaterialUtils.findSupplierNameById(req.getDeliverId()));
        }
        order.setStatus(DeliverOrderConstants.STATUS_WAIT_DELIVER);
        order.setPattern("2");
        if (EmpRoleConstants.SUPPLY_CHAIN.equals(req.getDeliverId())) {
            order.setPattern("3");
            order.setOutWarehouseId(req.getOutWarehouseId());
            order.setStatus(DeliverOrderConstants.STATUS_WAIT_DELIVER);
            //跳过审核 0 待发货  1待审核
            order.setSendStatus("0");//待审核
        }
        List<AllocationDetailReq> details = req.getDetails();
        BigDecimal totalDeliverAmount = BigDecimal.ZERO;// 实发总数
        BigDecimal totalAmount=BigDecimal.ZERO;
        BigDecimal predictAmount=BigDecimal.ZERO; //预估授信额度
        List<CrmSupplyMaterialDeliverOrderDetail> li=new ArrayList<>();
        for (AllocationDetailReq detail : details) {
            CrmSupplyMaterialDeliverOrderDetail orderDetail = deliverDetailDao.get(detail.getDetailId());
//            if (orderDetail.getApplyAmount().compareTo(detail.getOutAmount()) < 0) {
//                throw new BusinessException("发货数量大于申请数量");
//            }
//            if (detail.getOutAmount().compareTo(BigDecimal.ZERO) == 0) {
//                throw new BusinessException("发货数量不能为0");
//            }
          /*  if (detail.getPurchasePrice().compareTo(BigDecimal.ZERO) == 0) {
                throw new BusinessException("采购价不能为0");
            }*/
            if (detail.getSalesPrice().compareTo(BigDecimal.ZERO) == 0) {
                throw new BusinessException("销售价不能为0");
            }
            orderDetail.setOutAmount(detail.getOutAmount());
            orderDetail.setSalesPrice(detail.getSalesPrice());
           /* orderDetail.setPurchasePrice(detail.getPurchasePrice());*/
//            orderDetail.setOutAmount(detail.getOutAmount());
            deliverDetailDao.save(orderDetail);
            li.add(orderDetail);
            totalDeliverAmount = totalDeliverAmount.add(detail.getOutAmount());
            // 处理库存冻结数量
            if (EmpRoleConstants.SUPPLY_CHAIN.equals(req.getDeliverId())) {
                if (detail.getOutAmount().compareTo(BigDecimal.ZERO) > 0){
                    materialStockService.addFrozeOutNum(EmpRoleConstants.SUPPLY_CHAIN, req.getOutWarehouseId(), orderDetail.getMaterialId(), detail.getOutAmount());
                }
               }
            SupplyMaterial material = materialDao.get(orderDetail.getMaterialId());
            if("0".equals(material.getMaterialAttribute()) && orderDetail.getOutAmount()!=null && orderDetail.getSalesPrice()!=null){
                totalAmount=totalAmount.add(orderDetail.getOutAmount().multiply(orderDetail.getSalesPrice()));
            }
            //重新计算订单授信额度
            predictAmount=predictAmount.add(detail.getSalesPrice().multiply(detail.getOutAmount()));
        }
        order.setPredictAmount(predictAmount);
//        if(StringUtil.equalsAny(order.getType(),"1","2","4")){
//            //判断物料总额和 代理商授信额
//            CrmTraderAccount account=accountDao.findByTraderId(order.getTraderId());
//            if (account == null) {
//                throw new BusinessException("请新增代理商的可授信额度!");
//            }
//            if(account.getBasicQuotaAmountBalance().compareTo(totalAmount)<0){
//                throw new BusinessException("代理商标准授信额不足，不能通过!");
//            }
//        }
        // 修改代理商账户
//        if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
//            account.setBasicQuotaAmountBalance(account.getBasicQuotaAmountBalance().subtract(totalAmount));
//            account.setMaxQuotaAmountBalance(account.getMaxQuotaAmountBalance().subtract(totalAmount));
//            accountDao.save(account);
//        }

        order.setTotalDeliverAmount(totalDeliverAmount);
        User user = UserUtils.getUser();

        if(!"a".equals(req.getDeliverId())){   // 分配 发货单位是供应商  那么需要启动审批流程 到 采购审批
            Record rd = FormUtils.getdefLatest(FormUtils.PURCHASE_ORDER_APPLICATION);
            if(rd == null){
                throw  new BusinessException("采购审批流程未定义，不可发布申请");
            }
            order.setSupplyId(req.getDeliverId());
            String processName="采购申请-"+user.getUserName()+'-'+ DateUtils.formatDate(now,"yyyy-MM-dd HH:mm:ss");
            String processInstanceId = flowableService.startProcessFlowable2(user, order.getId(), rd, FormUtils.PURCHASE_ORDER_APPLICATION, now, user.getUserName(),req.getAllocationRemark(),processName,"","");
            logger.info(">>>>>>>>>>>>>allocation processInstanceId:{} ", processInstanceId);
            order.setPurchaseProcessInstanceId(processInstanceId);
            order.setPurchaseOrderExamineStatus(BondApplyConstant.APPLYSTATUS_ONE);
            order.setProcessDefId(rd.getStr("id"));

            order.setPurchaseOperateUserIds(user.getId()+","+rd.getStr("oneAuditUseId"));
            String taskName=FormUtils.getOneStepTaskName(rd.getStr("id"));
            order.setTaskName(taskName);

            logger.info(">>>>>>>>>>>>>>allocation>>>>>>>>>processInstanceId:{},taskName:{}", processInstanceId, taskName);
            order.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_APPROVAL);
        }

        //保存过程信息
        deliverOrderMsgDao.saveOrderOpe(order.getId(), "采购分配", user.getUserName(), user.getId(), DeliverOrderConstants.OPT_DIS);
        deliverDao.save(order);

        //status = 5 待发货的订单 生成小E销售单
        CompletableFuture<Void> future =CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(5000);
                if(DeliverOrderConstants.STATUS_WAIT_DELIVER.equals(order.getStatus())){
                    //"02".equals(way)?"已付货款":"材料扣款结算");//扣款方式
                    if ("5".equals(order.getType())){
                        applicationDetailService.insertQQ(order.getId(),"02"); // 小E或代理商销售单
                    }else {
                        applicationDetailService.insertQQ(order.getId(),"03"); // 甲供材料领用单
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
                logger.error(e.getMessage(), e);
            }
        });

       /* String gs="上海能辉科技有限公司";//创建公司
        String djlx="小E或代理商销售单";//单据类型
        String temp="合作伙伴物资需求单";//单据模板
        String code=order.getNumber();//单据编码
        String time=DateUtil.now();//业务日期
        String dlgs=order.getPlaceName();//公司名称
        String people=order.getAddress();//接收人
        String xm=req.getId();//项目
        String qx=order.getCity()+order.getArea();//地区
        String ztgs="贵州能辉科技有限公司";//主体公司
        String money="已付货款";//扣款方式

        for(CrmSupplyMaterialDeliverOrderDetail obj:li){
            String id= obj.getMaterialId();
            String sql=" select qq_material_code as qqMaterialCode,cs_shui_lv as csShuiLv,price from crm_supply_material_project_price where status='0' and qq_project_code=(select qq_code from crm_supply_material where id='"+id+"') limit 1";
            List<Record> records=Db.find(sql);
            String qqMaterialCode="";//项目编码
            String csShuiLv="";//税率
            String price="";//金额
            for(Record rd:records){
                qqMaterialCode= rd.getStr("qqMaterialCode");
                csShuiLv= rd.getStr("csShuiLv");
                price= rd.getStr("price");
            }


            double salesPrice=Double.valueOf(String.valueOf(obj.getSalesPrice()));//提交单价
            int num=Integer.valueOf(String.valueOf(obj.getOutAmount()));//提交数量
            double totalJE=num*salesPrice;//金额
            double wsJe= new BigDecimal(totalJE/(1+Double.valueOf(csShuiLv))).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();//无税金额
            double wsDj= new BigDecimal(salesPrice/(1+Double.valueOf(csShuiLv))).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue();//无税单价


        }*/


        //关联电站
       /* if (StringUtil.isNotBlank(req.getEntryIds())) {
            StringBuilder sb = new StringBuilder();
            sb.append("update crm_customer_entry set deliver_id='").append(order.getId()).append("' ");
            sb.append("where deliver_id is null and id in(").append(SqlUtils.inParam(req.getEntryIds().split(","))).append(") ");
            SQLQuery sqlQuery = customerEntryDao.getSession().createSQLQuery(sb.toString());
            sqlQuery.executeUpdate();
        }*/
    }

    /**
     * 驳回
     * @param id
     * @param operator
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public  int reject(String id,Operator operator) {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(id);
        //发货审核驳回
        deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.FHD_SH_NOT, "", operator);
        if (StringUtil.isNotBlank(order.getOutWarehouseId())) {
            List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(order.getId());
            for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
                materialStockDao.unFrozeStock(detail.getMaterialId(), order.getOutWarehouseId(), detail.getOutAmount());
            }
        }
        StringBuilder updateSql=new StringBuilder();
        updateSql.append("  update crm_supply_material_deliver_order set status=2 where id=? ");
        int result=Db.update(updateSql.toString(),id);
        updateQQ(id);
        return result;
    }

    /**
     * 删除小e销售单
     * @param orderId
     * @return
     */
    private  int updateQQ(String orderId){
        // 获取关联的小E销售单信息
        StringBuilder querySql=new StringBuilder();
        querySql.append(" select id,order_id,qq_code,qq_id from crm_supply_material_deliver_order_qq where status='0' and order_id=?  limit 1 ");
        // 将关系表删除
        StringBuilder updateSql=new StringBuilder();
        updateSql.append(" update crm_supply_material_deliver_order_qq set status='1' where id=? ");
        List<Record> records = Db.find(querySql.toString(), orderId);
        for(Record rd:records){
            String qqId=rd.getStr("qq_id");
            String id = rd.getStr("id");
            Db.update(updateSql.toString(), id);
            OpenapiTemplate.flow(qqId);
        }
        return 0;
    }

    /**
     * 分配驳回
     */
    @Transactional(rollbackFor = Exception.class)
    public void allocationReject(CommonRejectReq req) {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(req.getId());
        if (!StrKit.notNull(order)) {
            throw new BusinessException("订单不存在");
        }
        if (!DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION.equals(order.getStatus()) && !DeliverOrderConstants.STATUS_DELIVER_REJECT.equals(order.getStatus()) && !DeliverOrderConstants.STATUS_SPLIT.equals(order.getStatus())) {
            throw new BusinessException("订单状态已变更");
        }
        User user = UserUtils.getUser();
        order.setStatus(DeliverOrderConstants.STATUS_ALLOCATION_REJECT);
        order.setOrderExamineStatus(DeliverOrderConstants.EXAMINE_STATUS_TWO);
        order.setCancelReason(req.getReason());
        deliverDao.save(order);
        deliverOrderMsgDao.saveOrderOpe(order.getId(), "分配驳回", user.getUserName(), user.getId(), DeliverOrderConstants.OPT_BH);
        //释放授信额
//        if (StringUtil.isNotBlank(order.getTraderId())) {
//            List<CrmSupplyMaterialDeliverOrderDetail> details=deliverDetailDao.listDetailByOrderId(order.getId());
//            BigDecimal totalAmount=BigDecimal.ZERO;
//            for(CrmSupplyMaterialDeliverOrderDetail detail:details){
//                if(detail.getOutAmount()!=null && detail.getSalesPrice()!=null){
//                    SupplyMaterial material = materialDao.get(detail.getMaterialId());
//                    if ("0".equals(material.getMaterialAttribute())) {
//                        totalAmount=totalAmount.add(detail.getOutAmount().multiply(detail.getSalesPrice()));
//                    }
//                }
//            }
//            // 修改代理商账户
//            if (totalAmount.compareTo(BigDecimal.ZERO) > 0) {
//                CrmTraderAccount account=accountDao.findByTraderId(order.getTraderId());
//                account.setBasicQuotaAmountBalance(account.getBasicQuotaAmountBalance().add(totalAmount));
//                account.setMaxQuotaAmountBalance(account.getMaxQuotaAmountBalance().add(totalAmount));
//                accountDao.save(account);
//            }
//        }
    }

    /**
     * 发货单并单
     */
    @Transactional(rollbackFor = Exception.class)
    public void mergeDeliverOrder(String ids, Operator operator) {
        List<String> orderIds = Arrays.asList(ids.split(","));
        List<CrmSupplyMaterialDeliverOrder> orderList = deliverDao.findByIds(orderIds);
        checkBeforeMerge(orderList);
        // 创建新订单
        CrmSupplyMaterialDeliverOrder mergeOrder = createMergeOrder(orderList, operator);
        List<CrmSupplyMaterialDeliverOrderDetail> list = new ArrayList<>();
        BigDecimal predictAmount=BigDecimal.ZERO; //预估授信额度
        for (CrmSupplyMaterialDeliverOrder order : orderList) {
            List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(order.getId());
            for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
                addDetails(list, detail.getMaterialId(), detail.getOutAmount(), detail.getApplyAmount(), detail.getMaterialSpec(), detail.getMaterialType(), detail.getSalesPrice(), detail.getPurchasePrice(), mergeOrder.getId());
            }
            predictAmount=predictAmount.add(order.getPredictAmount());
            order.setStatus(DeliverOrderConstants.STATUS_MERGED);
            order.setRelateNo(StringUtil.appendMultiString(order.getRelateNo(), mergeOrder.getNumber()));
            deliverDao.save(order);
            // 操作记录
            deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.OPT_MERGE, "", operator);
        }
        //合并后的订单的预估授信额度
        mergeOrder.setPredictAmount(predictAmount);
        deliverDetailDao.save(list);
        // 维护物料类型数量和物料总数
        mergeOrder.setMaterialTypeAmount(new BigDecimal(list.size()));
        mergeOrder.setTotalApplyAmount(list.stream().map(CrmSupplyMaterialDeliverOrderDetail::getApplyAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
        deliverDao.save(mergeOrder);
    }

    /**
     * 合并订单校验
     * 订单数须大于2个、必须是同一个代理商同一个入库仓库的订单才可合并、且待匹配状态的
     *
     * @param list
     */
    public void checkBeforeMerge(List<CrmSupplyMaterialDeliverOrder> list) {
        if (list.isEmpty()) {
            throw new BusinessException("订单不存在");
        }
        if (list.size() < 2) {
            throw new BusinessException("合并订单数不少于2个");
        }
        // 校验订单状态
        List<CrmSupplyMaterialDeliverOrder> statusList = list.stream().filter(o -> DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION.equals(o.getStatus())).collect(Collectors.toList());
        if (statusList.size() != list.size()) {
            throw new BusinessException("仅待匹配订单可合并");
        }
        Set<String> traders = list.stream().map(CrmSupplyMaterialDeliverOrder::getTraderId).collect(Collectors.toSet());
        if (traders.size() > 1) {
            throw new BusinessException("订单非同一代理商");
        }
        Set<String> inWarehouseList = list.stream().map(CrmSupplyMaterialDeliverOrder::getInWarehouseId).collect(Collectors.toSet());
        if (inWarehouseList.size() > 1) {
            throw new BusinessException("订单非同一入库仓");
        }
        Set<String> qqProjectCode = list.stream().map(CrmSupplyMaterialDeliverOrder::getQqProjectCode).collect(Collectors.toSet());
        if (qqProjectCode.size() > 1) {
            throw new BusinessException("订单非同一企企项目");
        }
    }

    /**
     * 创建发货单合并订单
     */
    public CrmSupplyMaterialDeliverOrder createMergeOrder(List<CrmSupplyMaterialDeliverOrder> source, Operator operator) {
        CrmSupplyMaterialDeliverOrder sourceOrder = source.get(0);
        CrmSupplyMaterialDeliverOrder mergeOrder = new CrmSupplyMaterialDeliverOrder();
        mergeOrder.setId(IdGen.uuid());
        Set<String> typeList = source.stream().map(CrmSupplyMaterialDeliverOrder::getType).collect(Collectors.toSet());
        List<String> numbers = source.stream().map(CrmSupplyMaterialDeliverOrder::getNumber).collect(Collectors.toList());
        List<String> relateNos = source.stream().map(CrmSupplyMaterialDeliverOrder::getRelateNo).collect(Collectors.toList());
        mergeOrder.setNumber(PlantformUtils.findOrderNumber("HB"));
        if (typeList.size() > 1) {
            mergeOrder.setType(DeliverOrderConstants.TYPE_MERGED);
        } else {
            mergeOrder.setType(typeList.iterator().next());
        }
//        mergeOrder.setType("3");
        mergeOrder.setPattern(sourceOrder.getPattern());
        mergeOrder.setProjectCode(sourceOrder.getProjectCode());
        mergeOrder.setTraderId(sourceOrder.getTraderId());
        mergeOrder.setQqProjectCode(sourceOrder.getQqProjectCode());
        mergeOrder.setApplyOrderId(sourceOrder.getApplyOrderId());
        mergeOrder.setRelateNo(StringUtil.join(relateNos, ","));// 关联单号
        mergeOrder.setInWarehouseId(sourceOrder.getInWarehouseId());
        mergeOrder.setOutWarehouseId(sourceOrder.getOutWarehouseId());
        mergeOrder.setProvince(sourceOrder.getProvince());
        mergeOrder.setCity(sourceOrder.getCity());
        mergeOrder.setArea(sourceOrder.getArea());
        mergeOrder.setAddress(sourceOrder.getAddress());
        mergeOrder.setAuditTime(sourceOrder.getAuditTime());
        mergeOrder.setCancelReason(sourceOrder.getCancelReason());
        mergeOrder.setWarehouseFailReason(sourceOrder.getWarehouseFailReason());
        mergeOrder.setAuditRemark(sourceOrder.getAuditRemark());
        mergeOrder.setRemarks(sourceOrder.getRemarks());
        mergeOrder.setPlaceBy(sourceOrder.getPlaceBy());
        mergeOrder.setPlaceName(sourceOrder.getPlaceName());
        mergeOrder.setPlaceTime(sourceOrder.getPlaceTime());
        mergeOrder.setCreateBy(sourceOrder.getCreateBy());
        mergeOrder.setCreator(sourceOrder.getCreator());
        mergeOrder.setCreateTime(sourceOrder.getCreateTime());
        mergeOrder.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION);
        mergeOrder.setOrderExamineStatus(sourceOrder.getOrderExamineStatus());
        mergeOrder.setProcessInstanceId(sourceOrder.getProcessInstanceId());
        mergeOrder.setPurchaseOrderExamineStatus(sourceOrder.getPurchaseOrderExamineStatus());
        mergeOrder.setPurchaseProcessInstanceId(sourceOrder.getProcessInstanceId());
        mergeOrder.setTaskName(sourceOrder.getTaskName());
        mergeOrder.setTaskId(sourceOrder.getTaskId());
        mergeOrder.setProcessDefId(sourceOrder.getProcessDefId());
        mergeOrder.setOperateUserIds(sourceOrder.getOperateUserIds());
        Set<String> insuranceFiles = new HashSet<>();
        Set<String> safetyFiles = new HashSet<>();
        Set<String> files = new HashSet<>();
        for (CrmSupplyMaterialDeliverOrder order : source) {
            if (StringUtil.isNotBlank(order.getInsuranceFiles())) {
                String[] split = order.getInsuranceFiles().split(",");
                insuranceFiles.addAll(Arrays.asList(split));
            }
            if (StringUtil.isNotBlank(order.getSafetyFiles())) {
                String[] split = order.getSafetyFiles().split(",");
                safetyFiles.addAll(Arrays.asList(split));
            }
            if (StringUtil.isNotBlank(order.getFileUrl())) {
                String[] split = order.getFileUrl().split(",");
                files.addAll(Arrays.asList(split));
            }
        }
        if (!insuranceFiles.isEmpty()) {
            mergeOrder.setInsuranceFiles(String.join(",",insuranceFiles));
        }
        if (!safetyFiles.isEmpty()) {
            mergeOrder.setSafetyFiles(String.join(",",safetyFiles));
        }
        if (!files.isEmpty()) {
            mergeOrder.setFileUrl(String.join(",",files));
        }
        deliverDao.save(mergeOrder);
        // 操作记录
        deliverOrderMsgDao.saveOptMsg(mergeOrder.getId(), DeliverOrderConstants.OPT_MERGE, "由合并订单生成，关联单号：" + StringUtil.join(numbers, ","), operator);
        return mergeOrder;
    }


    /**
     * 发货打回
     * 改变发货单状态至，释放冻结库存
     */
    @Transactional(rollbackFor = Exception.class)
    public void deliverReject(CommonRejectReq req, Operator operator) {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(req.getId());
        if (!StrKit.notNull(order)) {
            throw new BusinessException("订单不存在");
        }
        if (!DeliverOrderConstants.STATUS_WAIT_DELIVER.equals(order.getStatus())) {
            throw new BusinessException("订单状态已变更");
        }
        order.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION);
        order.setWarehouseFailReason(req.getReason());
        deliverDao.save(order);
        if (StringUtil.isNotBlank(order.getOutWarehouseId())) {
            List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(order.getId());
            for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
                materialStockDao.unFrozeStock(detail.getMaterialId(), order.getOutWarehouseId(), detail.getOutAmount());

            }
        }
        deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.OPT_DH, req.getReason(), operator);
        //弃审小E销售单
        updateQQ(order.getId());


        //初始化关联电站
    /*    if (customerEntryDao.findEntryByDeliverId(order.getId()) > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append("update crm_customer_entry set deliver_id=null ");
            sb.append("where deliver_id = '").append(order.getId()).append("' ");
            SQLQuery sqlQuery = customerEntryDao.getSession().createSQLQuery(sb.toString());
            sqlQuery.executeUpdate();
        }*/
    }

    /**
     * 发货审核
     * 改变发货单状态至，释放冻结库存
     */
    @Transactional(rollbackFor = Exception.class)
    public void passThrough(String id,String type,String examineRemark, Operator operator) {
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(id);
        if (!StrKit.notNull(order)) {
            throw new BusinessException("订单不存在");
        }
        if (!DeliverOrderConstants.STATUS_WAIT_DELIVER.equals(order.getStatus())) {
            throw new BusinessException("订单状态已变更");
        }
        //  BigDecimal totalAmount = BigDecimal.ZERO;
        //  BigDecimal adjustAmount = BigDecimal.ZERO;
        if("1".equals(type)){
            //审核通过
            order.setSendStatus("0");//审核通过 --待发货
        }else{
            order.setSendStatus("3");//审核不通过
            order.setStatus("2");//待分配
        }
        order.setExamineRemark(examineRemark);
        //更新订单状态
        deliverDao.save(order);
        //操作记录
        if ("1".equals(type)) {
            //审核通过
            deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.FHD_SH_TG, examineRemark, operator);
        } else {
            deliverOrderMsgDao.saveOptMsg(order.getId(), DeliverOrderConstants.FHD_SH_NOT, examineRemark, operator);
            if (StringUtil.isNotBlank(order.getOutWarehouseId())) {
                List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(order.getId());
                for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
                    materialStockDao.unFrozeStock(detail.getMaterialId(), order.getOutWarehouseId(), detail.getOutAmount());

                }
            }
            //初始化关联电站
     /*   if (customerEntryDao.findEntryByDeliverId(order.getId()) > 0) {
            StringBuilder sb = new StringBuilder();
            sb.append("update crm_customer_entry set deliver_id=null ");
            sb.append("where deliver_id = '").append(order.getId()).append("' ");
            SQLQuery sqlQuery = customerEntryDao.getSession().createSQLQuery(sb.toString());
            sqlQuery.executeUpdate();
        }*/
        }


    }

    @Transactional(rollbackFor = Exception.class)
    public void deliverRejectBatch(CommonRejectReq req) {
        String ids = req.getId();
        String reson = req.getReason();
        String content="拒发货";
        User user = UserUtils.getUser();
        short type=DeliverOrderConstants.OPT_REFUSE;
        String[] idArr = ids.split(",");
        for (String id : idArr) {
            CrmSupplyMaterialDeliverOrder order = deliverDao.get(id);
            if (!StrKit.notNull(order)) {
                throw new BusinessException("订单不存在");
            }
            if (!DeliverOrderConstants.STATUS_WAIT_DELIVER.equals(order.getStatus())) {
                throw new BusinessException("订单状态已变更");
            }
            if ("1".equals(order.getPattern())) {
                order.setStatus(DeliverOrderConstants.STATUS_REFUSE);
            } else {
                order.setStatus(DeliverOrderConstants.STATUS_DELIVER_REJECT);
            }
            order.setWarehouseFailReason(reson);
            deliverDao.save(order);
            if (!"1".equals(order.getPattern()) && StringUtil.isNotBlank(order.getOutWarehouseId())) {
                List<CrmSupplyMaterialDeliverOrderDetail> details = deliverDetailDao.listDetailByOrderId(order.getId());
                for (CrmSupplyMaterialDeliverOrderDetail detail : details) {
                    materialStockDao.unFrozeStock(detail.getMaterialId(), order.getOutWarehouseId(), detail.getOutAmount());

                }
            }
            //保存过程信息
            deliverOrderMsgDao.saveOrderOpe(order.getId(),content,user.getUserName(),user.getId(),type);
        }
    }

    /**
     *代理商发起订单申请时，按照申请物料规格的最高价判断代理商授信额度
     * 代理商提交物料订单时（包含通过赊销下单和自主下单），先根据申请的物料规格的最高价判断代理商的授信余额，满足时才能提交申请。
     * 提交后不扣减授信额度，在发货出库后再根据匹配的具体物料零售价扣减授信余额；
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveApplyOrder(ApplyOrderReq req, Operator operator) {
        logger.info("saveApplyOrder 自主下单 req:{}",req.toString());
        String id =IdGen.uuid();
        User user = UserUtils.getUser();
        Date date = new Date();
        CrmSupplyMaterialDeliverOrder apply ;
        String formId="";
        String processName="";
        if(StringUtil.isBlank(req.getId())){
            apply = new CrmSupplyMaterialDeliverOrder();
            if("5".equals(req.getType())){
                // 对应现金下单
                apply.setNumber(PlantformUtils.findOrderNumber("ZJ"));
            }else{
                // 对应赊销下单
                apply.setNumber(PlantformUtils.findOrderNumber("ZZ"));

            }
            apply.setId(id);
            apply.setCreateTime(date);
            apply.setCreateBy(operator.getUserId());
            apply.setCreator(operator.getUserName());
            apply.setType(req.getType());
            apply.setTraderId(CrmUtils.getCurrentTraderId(operator.getUserId()));
            apply.setPlaceBy(apply.getTraderId());
            apply.setPlaceName(operator.getUserName());
            apply.setPlaceTime(date);
            apply.setVersion(0);
            if("1".equals(req.getType())){
                //电站下单-- 修改电站下单状态
                for (String enid : req.getEntryIds().split(",")) {
                    CustomerEntry customerEntry = customerEntryDao.get(enid);
                    customerEntry.setAcceptFlag("1");//已下单
                    customerEntryDao.save(customerEntry);
                }

            }

        }else{
            apply = deliverDao.get(req.getId());
            if(com.sifang.modules.sunshine.SystemSetting.utils.StringUtil.isNotBlank(apply.getApplyOrderId())){
                for (String enid : apply.getApplyOrderId().split(",")) {
                    if(!req.getEntryIds().contains(enid)){
                        CustomerEntry customerEntry = customerEntryDao.get(enid);
                        customerEntry.setAcceptFlag("0");//已下单
                        customerEntryDao.save(customerEntry);
                    }
                }
            }
            if("1".equals(req.getType())){
                //电站下单-- 修改电站下单状态
                for (String enid : req.getEntryIds().split(",")) {
                    if(!apply.getApplyOrderId().contains(enid)){
                        CustomerEntry customerEntry = customerEntryDao.get(enid);
                        customerEntry.setAcceptFlag("1");
                        customerEntryDao.save(customerEntry);
                    }
                }

            }
        }
        apply.setApplyOrderId(req.getEntryIds());
        apply.setInWarehouseId(req.getInWarehouseId());
        apply.setProvince(req.getProvince());
        apply.setCity(req.getCity());
        apply.setArea(req.getArea());
        apply.setAddress(req.getAddress());
        apply.setRemarks(req.getRemark());
        apply.setInsuranceFiles(req.getInsuranceFiles());
        apply.setSafetyFiles(req.getSafetyFiles());
        apply.setOrderExamineStatus(DeliverOrderConstants.EXAMINE_STATUS_ONE);
        apply.setQqProjectCode(req.getQqProjectCode());
        apply.setFileUrl(req.getFiles());
        //获取所有物料
        Map<String,Record> maps= Maps.newHashMap();
        if("5".equals(req.getType())){
            Map<String,String> reqmap = Maps.newHashMap();
            reqmap.put("materialTypeId","4") ;
            List<Record> recordList = materialDao.findMaterialList(null,reqmap);
            for(Record rd:recordList){
                maps.put(rd.getStr("id"),rd);
            }
            formId=FormUtils.BRACKET_ORDER_APPLY;
            processName="现金下单申请-";
        }else{
            formId=FormUtils.SUPPLY_ORDER_APPLICATION;
            processName="赊销下单申请-";
        }
        //=newItems.stream().collect(Collectors.toMap(CrmSupplyMaterialDeliverOrderDetail::getId, e -> e, (b, a) -> a));


        //添加明细表
        List<CrmSupplyMaterialDeliverOrderDetail> detailList = Lists.newArrayList();//addMaterialDetails(gatherList, apply.getId());
        // setTotalData(apply, detailList);
        String currentTraderId = CrmUtils.getCurrentTraderId(user);
        CrmTrader trader = traderDao.get(currentTraderId);
        //String qqProjectCode = trader.getQqProjectCode();
        BigDecimal predictAmount=BigDecimal.ZERO; //预估授信额度
        int sort =1;
        for (ApplyOrderDetailReq detail : req.getDetails()) {
            CrmSupplyMaterialDeliverOrderDetail deliverDetail = new CrmSupplyMaterialDeliverOrderDetail();
            if (StringUtil.isNotBlank(detail.getTargetId())) {
                Record rds = maps.get(detail.getTargetId());
                if(rds == null){
                    throw new BusinessException("物料不存在");
                }
                deliverDetail.setMaterialId(detail.getTargetId());
                deliverDetail.setMaterialType(rds.getStr("typeName"));
                deliverDetail.setMaterialSpec(rds.getStr("material_specs"));
                String qqMaterialCode = rds.getStr("qq_code");
                Record materialProjectPrice = projectPriceService.findPriceByCodes(req.getQqProjectCode(), qqMaterialCode);
//                rd.set("customer_price",materialProjectPrice.getBigDecimal("price"));
                if (materialProjectPrice == null){
                    throw new BusinessException("销售价未维护");
                }else {
                    if (materialProjectPrice.getBigDecimal("price").compareTo(BigDecimal.ZERO) == 0){
                        throw new BusinessException("销售价未维护");
                    }
                }
//                if (rds.getBigDecimal("customer_price").compareTo(BigDecimal.ZERO) == 0) {
//                    throw new BusinessException("销售价未维护");
//                }
//                deliverDetail.setSalesPrice(rds.getBigDecimal("customer_price"));
                deliverDetail.setSalesPrice(materialProjectPrice.getBigDecimal("price"));
                predictAmount=predictAmount.add(materialProjectPrice.getBigDecimal("price").multiply(detail.getAmount()));

            } else if (StringUtil.isNotBlank(detail.getMaterialType())) {
                deliverDetail.setMaterialType(detail.getMaterialType());
                deliverDetail.setMaterialSpec(detail.getMaterialSpecs());
                //按照申请物料规格的最高价判断代理商授信额度
                BigDecimal maxPrice=materialDao.getMaxPriceBySpec(deliverDetail.getMaterialType(),deliverDetail.getMaterialSpec(),req.getQqProjectCode());
                deliverDetail.setSalesPrice(maxPrice);
                predictAmount=predictAmount.add(maxPrice.multiply(detail.getAmount()));
            } else {
                throw new BusinessException("物料不存在");
            }
            deliverDetail.setMainId(apply.getId());
//            Record smInfo = materialDao.findByTypeAndName(detail.getMaterialType(), detail.getMaterialSpecs());
//            if(smInfo!= null){
//                Integer minApplyAmount = smInfo.getInt("min_apply_amount");
//                int applyAmount = detail.getAmount().intValue();
//                if(applyAmount % minApplyAmount != 0){
//                    throw new BusinessException("第"+sort+"行物料申请数量必须为其最少发货单位的整数倍");
//                }
//            }else if (detail.getTargetId() != null && detail.getTargetId() !=""){
//                SupplyMaterial materialInfo = materialDao.get(detail.getTargetId());
//                int minApplyAmount = materialInfo.getMinApplyAmount();
//                int applyAmount = detail.getAmount().intValue();
//                if(applyAmount % minApplyAmount != 0){
//                    throw new BusinessException("第"+sort+"行物料申请数量必须为其最少发货单位的整数倍");
//                }
//            }
            deliverDetail.setApplyAmount(detail.getAmount());
            //成本价
            BigDecimal maxPurchasePrice = deliverDao.findMaxPurchasePrice(detail.getMaterialType(), detail.getMaterialSpecs());
            deliverDetail.setPurchasePrice(maxPurchasePrice);
            deliverDetail.setOutAmount(detail.getAmount());
            deliverDetail.setInAmount(BigDecimal.ZERO);
            deliverDetail.setSort(sort);
            deliverDetail.setStatus("0");
            detailList.add(deliverDetail);
            sort++;
        }
        apply.setPredictAmount(predictAmount);//预估授信额度
        if("1".equals(req.getActionType())){ //暂存
            apply.setStatus(DeliverOrderConstants.STATUS_TEMPLE_SAVE);
            apply.setOrderExamineStatus(DeliverOrderConstants.EXAMINE_STATUS_ZERO);
            apply.setProcessInstanceId(null);
        }else{
            logger.info(">>>>>>>>>>自主下单预估授信额:{}",predictAmount);

            if(StrKit.isBlank(apply.getProcessInstanceId()) ) {
                deliverOrderMsgDao.saveOptMsg(apply.getId(), DeliverOrderConstants.OPT_CREATE, "", operator);
                //提交流程
                Record rd = FormUtils.getdefLatest(formId);
                if(rd == null){
                    throw  new BusinessException("流程未定义，不可发布申请");
                }
                String traderName= CrmUtils.getTraderNameById(apply.getTraderId());
                processName=processName+user.getUserName()+'-'+ DateUtils.formatDate(date,"yyyy-MM-dd HH:mm:ss")+"("+traderName+")";
                //启动流程
                String processInstanceId=flowableService.startProcessFlowable(user,apply.getId(),rd,formId,date,operator.getUserName(),req.getRemark(),processName,trader.getId());
                apply.setProcessInstanceId(processInstanceId);
                apply.setOrderExamineStatus(BondApplyConstant.APPLYSTATUS_ONE);
                apply.setProcessDefId(rd.getStr("id"));

                String taskName=FormUtils.getOneStepTaskName(rd.getStr("id"));
                apply.setTaskName(taskName);
                apply.setOperateUserIds(user.getId()+","+rd.getStr("oneAuditUseId"));
                logger.info(">>>>>>>>>>>>>>saveApplyOrder>>>>>>>>>taskName:{},processInstanceId:{}",taskName,processInstanceId);

            }else if("3".equals(apply.getStatus()) ) {
                //分配打回得重更新提交
                deliverOrderMsgDao.saveOptMsg(apply.getId(), DeliverOrderConstants.OPT_CREATE, "", operator);
                //提交流程
                Record rd = FormUtils.getdefLatest(formId);
                if(rd == null){
                    throw  new BusinessException("流程未定义，不可发布申请");
                }
                //启动流程
                String processInstanceId=flowableService.startProcessFlowable(user,apply.getId(),rd,formId,date,operator.getUserName(),req.getRemark(),processName,trader.getId());
                apply.setProcessInstanceId(processInstanceId);
                apply.setOrderExamineStatus(BondApplyConstant.APPLYSTATUS_ONE);
                apply.setProcessDefId(rd.getStr("id"));

                String taskName=FormUtils.getOneStepTaskName(rd.getStr("id"));
                apply.setTaskName(taskName);
                apply.setOperateUserIds(user.getId()+","+rd.getStr("oneAuditUseId"));
                logger.info(">>>>>>>>>>>>>>saveApplyOrder>>>>>>>>>taskName:{},processInstanceId:{}",taskName,processInstanceId);

            }else if(StringUtil.isNotBlank(apply.getProcessInstanceId()) ){
                //操作记录
                deliverOrderMsgDao.saveOptMsg(apply.getId(), DeliverOrderConstants.OPT_EDIT, "", operator);
              /*  Task task = taskService.createTaskQuery().processInstanceId(apply.getProcessInstanceId()).taskAssignee(user.getId()).singleResult();
                flowableService.approveTask2(task,"编辑后提交",apply.getId(),user, formId);*/

            }
            apply.setStatus(DeliverOrderConstants.STATUS_WAIT_AUDIT);
        }

        if(StringUtil.isNotBlank(req.getId())){
            //编辑的话  删除历史数据
            deliverDetailDao.deleteDetailByOrderId(req.getId());
        }
        apply.setMaterialTypeAmount(new BigDecimal(detailList.size()));
        apply.setTotalApplyAmount(detailList.stream().map(CrmSupplyMaterialDeliverOrderDetail::getApplyAmount).reduce(BigDecimal.ZERO, BigDecimal::add));

        deliverDao.save(apply);
        deliverDetailDao.save(detailList);
    }

    public Record findOrderCount(String traderId){

        Record re = deliverDao.findOrderCount(traderId);
        Record recount= deliverDao.findOrderRunturn(traderId);
        re.setColumns(recount);

        return re;
    }

    public List<Record> findDetails(String orderId) {
        List<Record> list = deliverDetailDao.findDetailsByOrderId(orderId);
        for (Record r : list) {
            r.set("returnNum",deliverDetailDao.findReturnNum(orderId,r.getStr("material_id")));
        }
        return list;
    }

    public boolean relationReturnOrder(String orderId) {
        Long cnt = Db.queryLong("SELECT COUNT(a.id) FROM crm_supply_material_return_order a WHERE a.relation_id=? AND a.status IN ('1','2','3')",orderId);
        if (cnt > 0) {
            return true;
        }
        return false;
    }

    public List<Record> findEntryList(String relateNo){
        if (StringUtil.isBlank(relateNo)) {
            return null;
        }
        SqlBuilder builder = new SqlBuilder();
        builder.line("SELECT a.id,a.power_station_code,a.product_line_name,a.project_name,a.project_code,a.scheme_name,a.design_capacity");
        builder.line("FROM crm_customer_entry a");
        builder.inst("WHERE a.deliver_id is null and a.power_station_code IN ",relateNo.split(","));
        return Db.find(builder.build(),builder.params());
    }

    @Transactional(rollbackFor = Exception.class)
    public Result updateReceiveInvoice(String orderId, String receiveInvoice) {
        if (StringUtil.isBlank(orderId)) {
            return Result.fail("orderId为空");
        }
        if (StringUtil.isBlank(receiveInvoice)) {
            return Result.fail("签收凭证为空");
        }
        CrmSupplyMaterialDeliverOrder order = deliverDao.get(orderId);
        order.setReceiveInvoice(receiveInvoice);
        deliverDao.save(order);
        return Result.ok();
    }
}
