package com.prolog.cs.base.gsp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.github.pagehelper.PageHelper;
import com.prolog.cs.base.gsp.dao.DxiGspGainslossesBillRecMapper;
import com.prolog.cs.base.gsp.dao.GspUnqualifiedLossDMapper;
import com.prolog.cs.base.gsp.dao.GspUnqualifiedLossMapper;
import com.prolog.cs.base.gsp.dao.OmsInventoryOrderMapper;
import com.prolog.cs.base.gsp.enums.GspUnqualifiedStatus;
import com.prolog.cs.base.gsp.model.DxiGspGainslossesBillRec;
import com.prolog.cs.base.gsp.model.GspUnqualifiedLoss;
import com.prolog.cs.base.gsp.model.GspUnqualifiedLossD;
import com.prolog.cs.base.gsp.model.OmsInventoryOrder;
import com.prolog.cs.base.gsp.resource.*;
import com.prolog.cs.base.gsp.service.GspUnqualifiedLossService;
import com.prolog.cs.base.gsp.vo.ErpUnqualifiedLossVo;
import com.prolog.cs.base.gsp.vo.GspUnqualifiedLossDVO;
import com.prolog.cs.basic.chain.model.cargo.BaseCargoOwnerMst;
import com.prolog.cs.basic.item.model.BaseMtlItemHealth;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.warehouse.model.BaseWmsWarehouseMst;
import com.prolog.cs.basic.warehouse.model.vo.WarehouseLocatorBasicInfo;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.*;
import com.prolog.upcloud.base.inventory.vo.*;
import com.prolog.upcloud.base.strategy.model.BusinessControl;
import com.prolog.upcloud.base.wh.operate.vo.OmsInventoryResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class GspUnqualifiedLossServiceImpl implements GspUnqualifiedLossService {

    @Autowired
    private GspUnqualifiedLossMapper mapper;

    @Autowired
    private GspUnqualifiedLossDMapper dMapper;

    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private WarehouseClient warehouseClient;

    @Autowired
    private ChainClient chainClient;

    @Autowired
    private StrategyClient strategyClient;

    @Autowired
    private DxiGspGainslossesBillRecMapper dxiGspGainslossesBillRecMapper;

    @Autowired
    private InventoryClient inventoryClient;

    @Autowired
    private OmsInventoryOrderMapper omsInventoryOrderMapper;

    // 业务控制参数识别号-是否开启erp审批 0: 关闭(默认，可不配置) 1: 开启
    @Value("${prolog.unqualifiedLoss.erpAuditRegCode:LOSS_ERP_AUDIT_ON}")
    private String erpAuditRegCode;

    @Value("${oms.omsInventoryResultUrl}")
    private String omsInventoryResultUrl;


    @Value("${erp.erpInventoryCallbackUrl}")
    private String erpInventoryCallbackUrl;


    @Override
    @Transactional
    public Boolean add(GspUnqualifiedLoss model) {
        //		if (StringUtils.isEmpty(model.getCargoOwnerId()))
        //			throw new ParameterException("货主不能为空");
        if (StringUtils.isEmpty(model.getWarehouseId()))
            throw new ParameterException("仓库不能为空");
        if (model.getGspUnqualifiedLossDList() == null || model.getGspUnqualifiedLossDList().size() == 0)
            throw new ParameterException("请选择商品");

        //请求仓库信息
        BaseWmsWarehouseMst wmsWarehouseMst = null;
        RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = warehouseClient.warehouse(model.getWarehouseId());
        if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
            wmsWarehouseMst = itemResultWarehouse.getData();
        }
        if (wmsWarehouseMst == null) {
            throw new ParameterException("仓库不能为空");
        }
        UserDTO userDTO = userTemplate.getUserDTO();
        String userId = userDTO.getId();
        String userName = userDTO.getNickname();
        String enterpriseId = userDTO.getEnterpriseId();
        Date date = new Date();

        // 获取是否开启erp审核的配置，并配置是否开启erp审核
        // 默认不开启(直接设置erp已审核通过状态)
        String status = GspUnqualifiedStatus.OUT_AUDIT_YES.getStatus();
        Boolean needErpAudit = this.isNeedErpAudit(model.getWarehouseId(), model.getCargoOwnerId(), enterpriseId);
        if (needErpAudit) {
            status = GspUnqualifiedStatus.START.getStatus();
        }

        model.setCreator(userId);
        String id = String.valueOf(SnowFlakeUtils.getId());
        model.setId(id);
        String code = "BSD" + id.substring(id.length() - 8);
        model.setCode(code);
        model.setCreatorName(userName);
        model.setGmtCreate(date);
        model.setModifier(userId);
        model.setModifierName(userName);
        model.setGmtModified(date);
        model.setEnterpriseId(enterpriseId);
        model.setStatus(status);
        model.setDcId(wmsWarehouseMst.getDcId());
        model.setEnterpriseId(enterpriseId);
        model.setSource("WMS");
        mapper.save(model);
        // 不合格品信息
        List<GspUnqualifiedLossD> dList = model.getGspUnqualifiedLossDList();
        List<InvStockScarp> invStockList = new ArrayList<>();
        for (int i = 0; i < dList.size(); i++) {
            GspUnqualifiedLossD dModel = dList.get(i);
            String unqualifiedQty = dModel.getUnqualifiedQty();
            String lossQty = dModel.getLossQty();
            if ((StringUtils.isBlank(unqualifiedQty) || StringUtils.isBlank(lossQty)) ||
              (new BigDecimal(unqualifiedQty)).compareTo(new BigDecimal(lossQty)) < 0) {
                throw new BizException("报损数量不能大于不合格数量：第" + (i + 1) + "行");
            }
            String sonId = String.valueOf(SnowFlakeUtils.getId());
            dModel.setId(sonId);
            dModel.setDcId(wmsWarehouseMst.getDcId());
            dModel.setWarehouseId(model.getWarehouseId());
            dModel.setEnterpriseId(enterpriseId);
            dModel.setLossId(id);
            dModel.setLossCode(code);
            if (StringUtils.isBlank(dModel.getLotNum()) && !StringUtils.isBlank(dModel.getManufacturerLotNum())) {
                dModel.setLotNum(dModel.getManufacturerLotNum());
            }
            dModel.setStatus(status);
            dModel.setDestroyingQty("0");
            dModel.setDestroyedQty("0");
            dModel.setCreator(userId);
            dModel.setCreatorName(userName);
            dModel.setGmtCreate(date);
            dModel.setModifier(userId);
            dModel.setModifierName(userName);
            dModel.setGmtModified(date);
            dModel.setSeqNo(Integer.toString((i + 1)));//对接单据行号
            dMapper.save(dModel);
            // 预占库存操作移动到审批动作中
            InvStockScarp invStockScarp=new InvStockScarp();
            invStockScarp.setBillId(id);
            invStockScarp.setLineBillId(sonId);
            invStockScarp.setWarehouseId(model.getWarehouseId());
            InvStockScrapDetail invStockScrapDetail=new InvStockScrapDetail();
            invStockScrapDetail.setBatchId(dModel.getBatchId());
            invStockScrapDetail.setLocatorId(dModel.getLocatorId());
            invStockScrapDetail.setQuantity(new BigDecimal(dModel.getLossQty()));
            invStockScarp.setDetails((new ArrayList<InvStockScrapDetail>(){{add(invStockScrapDetail);}}));
            invStockList.add(invStockScarp);
        }

        // 不做erp审核则无需保存
        if (needErpAudit) {
            saveDxiOrder(model);
        }
        RestMessage upKeepDictResult = inventoryClient.scrapStock(invStockList);
        log.info("调用库存接口scrapStock,入参为："+ JSON.toJSONString(invStockList)+"，返回为："+JSON.toJSONString(upKeepDictResult));
        if (upKeepDictResult==null || !upKeepDictResult.isSuccess()) {
            throw new BizException("调用库存异常:"+ (upKeepDictResult == null?"返回结果为null":upKeepDictResult.getMessage()));
        }
        return needErpAudit;
    }


    @Override
    @Transactional
    public void delIds(List<String> pkIdList) {
        pkIdList.stream().forEach(p ->
          this.mapper.deleteById(p, GspUnqualifiedLoss.class));
    }

    @Override
    public Page<GspUnqualifiedLoss> listPage(String warehouseId, String cargoOwnerId, String status, Integer pageSize, Integer pageNum) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();

        // 获取是否开启erp审核的配置，并配置是否开启erp审核
        if (this.isNeedErpAudit(warehouseId, cargoOwnerId, enterpriseId)) {
            // 需要放在 PageHelper 之前，防止被影响
            // 需要erp审核时，刷新erp的审核状态
            this.updateLossStatus(warehouseId, cargoOwnerId, enterpriseId);
        }

        PageHelper.startPage(pageNum, pageSize);
        Criteria crt = Criteria.forClass(GspUnqualifiedLoss.class);
        Restriction r1 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
        Restriction r3 = Restrictions.eq("status", status);
        Restriction r4 = StringUtils.isEmpty(cargoOwnerId) ? null : Restrictions.eq("cargoOwnerId", cargoOwnerId);
        crt.setOrder(Order.newInstance().desc("gmtCreate"));
        crt.setRestriction(Restrictions.and(r1, r2, r3, r4));
        List<GspUnqualifiedLoss> list = mapper.findByCriteria(crt);
        //请求仓库信息
        String warehouseName = null;
        RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = warehouseClient.warehouse(warehouseId);
        if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
            warehouseName = itemResultWarehouse.getData().getWarehouseName();
        }
        //组合id
        String[] locatorIds = list.stream().map(GspUnqualifiedLoss::getCargoOwnerId).distinct().toArray(String[]::new);
        //请求货位信息
        RestMessage<Map<String, BaseCargoOwnerMst>> locatorResult = chainClient.getCargoOwnerMstByIds(locatorIds);
        if (locatorResult == null || locatorResult.getData() == null) {
            throw new BizException("货主数据异常");
        }
        for (GspUnqualifiedLoss gspUnqualifiedLoss : list) {
            gspUnqualifiedLoss.setWarehouseName(warehouseName);
            if (locatorResult.getData().get(gspUnqualifiedLoss.getCargoOwnerId()) != null) {
                gspUnqualifiedLoss.setCargoOwnerName(locatorResult.getData().get(gspUnqualifiedLoss.getCargoOwnerId()).getCargoOwnerName());
            }
        }
        return PageUtils.getPage(list);
    }

    /**
     * 找出所有还是初始状态的汇总表数据，更新其ERP的审批状态
     *
     * @param warehouseId
     * @param cargoOwnerId
     * @param enterpriseId
     */
    private void updateLossStatus(String warehouseId, String cargoOwnerId, String enterpriseId) {
        // 找出所有还是初始状态的汇总表数据
        Criteria crt = Criteria.forClass(GspUnqualifiedLoss.class);
        Restriction r1 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
        Restriction r3 = Restrictions.eq("status", GspUnqualifiedStatus.START.getStatus());
        Restriction r4 = StringUtils.isEmpty(cargoOwnerId) ? null : Restrictions.eq("cargoOwnerId", cargoOwnerId);
        crt.setRestriction(Restrictions.and(r1, r2, r3, r4));
        List<GspUnqualifiedLoss> list = mapper.findByCriteria(crt);
        String[] lossIds = list.stream().map(GspUnqualifiedLoss::getId).distinct().toArray(String[]::new);

        if (ObjectUtils.isNotNull(lossIds)) {
            // 找出汇总数据对应的ERP审批通过的明细数据
            Criteria crtD = Criteria.forClass(GspUnqualifiedLossD.class);
            Restriction rD1 = Restrictions.in("lossId", lossIds);
            //			Restriction rD2 = Restrictions.eq("status", GspUnqualifiedStatus.ERP_AUDIT_YES.getStatus());
            crtD.setRestriction(Restrictions.and(rD1));
            List<GspUnqualifiedLossD> listD = dMapper.findByCriteria(crtD);
            // 分辨ERP还未审核、审核部分或全部通过、全部审核都不通过的汇总数据
            List<String> lossIdsErpYes = new ArrayList<>();
            List<String> lossIdsErpNo = new ArrayList<>();
            for (String lossId : lossIds) {
                String tag = "";
                for (GspUnqualifiedLossD gspUnqualifiedLossD : listD) {
                    if (lossId.equals(gspUnqualifiedLossD.getLossId())) {
                        // 还未审核
                        if (gspUnqualifiedLossD.getStatus().equals(GspUnqualifiedStatus.START.getStatus())) {
                            tag = "";
                            break;
                        }
                        // 有审核通过的数据
                        if (gspUnqualifiedLossD.getStatus().equals(GspUnqualifiedStatus.OUT_AUDIT_YES.getStatus())) {
                            tag = "yes";
                        }
                        // 有审核驳回的数据
                        if (gspUnqualifiedLossD.getStatus().equals(GspUnqualifiedStatus.OUT_AUDIT_NO.getStatus())) {
                            if (!tag.equals("yes")) {
                                tag = "no";
                            }
                        }
                    }
                }
                if (tag.equals("yes")) {
                    lossIdsErpYes.add(lossId);
                }
                if (tag.equals("no")) {
                    lossIdsErpNo.add(lossId);
                }
            }

            if (!lossIdsErpYes.isEmpty() || !lossIdsErpNo.isEmpty()) {
                // 分别更新汇总单的状态
                Criteria crtUpdate = Criteria.forClass(GspUnqualifiedLoss.class);
                Restriction rYes = Restrictions.in("id", lossIdsErpYes.toArray(new String[lossIdsErpYes.size()]));
                Restriction rNo = Restrictions.in("id", lossIdsErpNo.toArray(new String[lossIdsErpNo.size()]));
                if (!lossIdsErpYes.isEmpty()) {
                    // 更新ERP审核部分或全部通过的数据
                    crtUpdate.setRestriction(rYes);
                    mapper.updateMapByCriteria(MapUtils.put("status", GspUnqualifiedStatus.OUT_AUDIT_YES.getStatus())
                      .put("gmtModified", new Date()).getMap(), crtUpdate);
                }
                if (!lossIdsErpNo.isEmpty()) {
                    // 更新ERP审核全部驳回的数据
                    crtUpdate.setRestriction(rNo);
                    mapper.updateMapByCriteria(MapUtils.put("status", GspUnqualifiedStatus.OUT_AUDIT_NO.getStatus())
                      .put("gmtModified", new Date()).getMap(), crtUpdate);
                }
            }
        }
    }

    @Override
    public List<GspUnqualifiedLossDVO> findDetailByMstId(String mstId) {
        Criteria crt = Criteria.forClass(GspUnqualifiedLossD.class);
        Restriction r1 = Restrictions.eq("lossId", mstId);
        // 不显示ERP审批驳回的内容
        Restriction r2 = Restrictions.ne("status", GspUnqualifiedStatus.OUT_AUDIT_NO.getStatus());
        crt.setOrder(Order.newInstance().asc("gmtCreate"));
        crt.setRestriction(Restrictions.and(r1, r2));
        List<GspUnqualifiedLossD> list = dMapper.findByCriteria(crt);
        List<GspUnqualifiedLossDVO> listRet = spellGspUnqualifiedLossDVOS(list);
        return listRet;
    }

    @Override
    public List<GspUnqualifiedLossDVO> spellGspUnqualifiedLossDVOS(List<GspUnqualifiedLossD> list) {
        String[] itemIds = list.stream().map(GspUnqualifiedLossD::getItemId).distinct().toArray(String[]::new);
        //请求商品信息
        RestMessage<List<BaseMtlItemMst>> itemResult = itemClient.getListByIds(itemIds);
        //转换并组装
        List<GspUnqualifiedLossDVO> listRet = new ArrayList<>();
        //组合id
        String[] ownerIds = list.stream().map(GspUnqualifiedLossD::getCargoOwnerId).distinct().toArray(String[]::new);
        //请求货位信息
        RestMessage<Map<String, BaseCargoOwnerMst>> restMessage = chainClient.getCargoOwnerMstByIds(ownerIds);
        //查询货位信息，得到库别 库区
        String[] locatorIdList = list.stream().map(GspUnqualifiedLossD::getLocatorId).toArray(String[]::new);
        RestMessage<List<WarehouseLocatorBasicInfo>> locationBasicInfos = warehouseClient.getLocationBasicInfos(locatorIdList);
        if (!locationBasicInfos.isSuccess() || locationBasicInfos.getData() == null) {
            throw new BizException("查询货位关联信息失败!请重试或联系管理员!");
        }
        List<WarehouseLocatorBasicInfo>  warehouselocators = locationBasicInfos.getData();


        String[] batchIds = list.stream().map(GspUnqualifiedLossD::getBatchId).distinct().toArray(String[]::new);
        RestMessage<List<BatchNumberListVO>> upKeepDictResult = inventoryClient.getBatchNumberBasicInfo(batchIds);
        for (GspUnqualifiedLossD gspUnqualifiedLossD : list) {
            GspUnqualifiedLossDVO gspUnqualifiedLossDVO = new GspUnqualifiedLossDVO();
            if (upKeepDictResult != null && upKeepDictResult.isSuccess() && upKeepDictResult.getData() != null) {
                for (int j = 0; j < upKeepDictResult.getData().size(); j++) {
                    BatchNumberListVO batchNumberListVO = upKeepDictResult.getData().get(j);
                    if (batchNumberListVO.getBatchId().equals(gspUnqualifiedLossD.getBatchId())) {
                        gspUnqualifiedLossDVO.setExpiredDate(batchNumberListVO.getBatchExpiredDate());
                        gspUnqualifiedLossDVO.setProductionDate(batchNumberListVO.getBatchProductionDate());
                        gspUnqualifiedLossDVO.setBatchExpiredDateShow(batchNumberListVO.getBatchExpiredDateShow());
                        gspUnqualifiedLossDVO.setBatchProductionDateShow(batchNumberListVO.getBatchProductionDateShow());
                        gspUnqualifiedLossDVO.setLotNum(batchNumberListVO.getManufacturerLotNum());
                    }
                }
            }
            if (restMessage != null && restMessage.getData() != null) {
                BaseCargoOwnerMst baseCargoOwnerMst = restMessage.getData().get(gspUnqualifiedLossD.getCargoOwnerId());
                if (baseCargoOwnerMst != null) {
                    gspUnqualifiedLossDVO.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
                    gspUnqualifiedLossDVO.setCargoOwnerName(baseCargoOwnerMst.getCargoOwnerName());
                }
            }
            if (itemResult.isSuccess() && itemResult.getData() != null) {
                BaseMtlItemMst itemBaseInfoVO = itemResult.getData().stream().filter(item -> item.getItemId().equals(gspUnqualifiedLossD.getItemId())).findFirst().orElse(null);
                if (itemBaseInfoVO != null) {
                    BeanUtils.copyProperties(itemBaseInfoVO, gspUnqualifiedLossDVO);
                    gspUnqualifiedLossDVO.setCountryOriginName(itemBaseInfoVO.getCountryOriginId());
                    gspUnqualifiedLossDVO.setManufacturerName(itemBaseInfoVO.getManufacturerId());
                    gspUnqualifiedLossDVO.setCaseConversionRate(itemBaseInfoVO.getCaseConversionRate());
                    BaseMtlItemHealth baseMtlItemHealth = itemBaseInfoVO.getBaseMtlItemHealth();
                    if (baseMtlItemHealth != null) {
                        gspUnqualifiedLossDVO.setItemHealthSuperviseFlag(baseMtlItemHealth.getItemHealthSuperviseflag() == 0 ? "否" : "是");
                        gspUnqualifiedLossDVO.setItemHealthListedLicensor(baseMtlItemHealth.getItemHealthListedLicensor());
                        gspUnqualifiedLossDVO.setItemHealthCategory(baseMtlItemHealth.getItemHealthCategoryName());
                        gspUnqualifiedLossDVO.setItemHealthApprovalNbr(baseMtlItemHealth.getItemHealthApprovalNbr());
                        gspUnqualifiedLossDVO.setItemHealthRegisterNbr(baseMtlItemHealth.getItemHealthRegisterNbr());
                    }
                }
            }

            BeanUtils.copyProperties(gspUnqualifiedLossD, gspUnqualifiedLossDVO);
            //库区库别
            for (WarehouseLocatorBasicInfo warehouselocator :warehouselocators) {
                if(warehouselocator.getWarehouseLocatorId().equals(gspUnqualifiedLossDVO.getLocatorId())){
                    gspUnqualifiedLossDVO.setWarehouseAreaName(warehouselocator.getWarehouseAreaName());
                    gspUnqualifiedLossDVO.setWarehouseAreaCategoryName(warehouselocator.getWarehouseAreaCategoryName());
                }
            }
            listRet.add(gspUnqualifiedLossDVO);
        }
        return listRet;
    }

    @TxTransaction
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAudit(List<GspUnqualifiedLoss> list, String status) throws Exception {
        UserDTO userDTO = userTemplate.getUserDTO();
        String userId = userDTO.getId();
        String userName = userDTO.getNickname();
        Date auditDate = new Date();
        for (GspUnqualifiedLoss gspUnqualifiedLoss : list) {
            gspUnqualifiedLoss.setModifier(userId);
            gspUnqualifiedLoss.setModifierName(userName);
            gspUnqualifiedLoss.setGmtModified(auditDate);
            gspUnqualifiedLoss.setAuditDate(auditDate);
            gspUnqualifiedLoss.setStatus(status);
            oneAudit(gspUnqualifiedLoss, status, auditDate);
        }
    }

    @Override
    @Transactional
    @TxTransaction
    public void oneAudit(GspUnqualifiedLoss gspUnqualifiedLoss, String status, Date auditDate) throws Exception {
        this.mapper.updateWithValidate(gspUnqualifiedLoss, p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
        Criteria crt = Criteria.forClass(GspUnqualifiedLossD.class);
        Restriction r1 = Restrictions.eq("lossId", gspUnqualifiedLoss.getId());
        Restriction r2 = Restrictions.eq("status", GspUnqualifiedStatus.OUT_AUDIT_YES.getStatus());
        crt.setRestriction(Restrictions.and(r1, r2));
        List<GspUnqualifiedLossD> dList = dMapper.findByCriteria(crt);
        if (dList == null || dList.size() == 0) {
            return;
        }
        List<GspUnqualifiedLossD> dtoDList = gspUnqualifiedLoss.getGspUnqualifiedLossDList();
        if(!"WMS".equals(gspUnqualifiedLoss.getSource()) && dtoDList !=null && dtoDList.size()>0){
            crt.setRestriction(Restrictions.and(r1));
            for (int i = 0; i < dList.size(); i++) {
                GspUnqualifiedLossD gspUnqualifiedLossD = dList.get(i);
                BigDecimal qty=BigDecimal.ZERO;
                for (int j = 0; j < dtoDList.size(); j++) {
                    GspUnqualifiedLossD unqualifiedLossD = dtoDList.get(j);
                    if(unqualifiedLossD.getId().equals(gspUnqualifiedLossD.getLossId())){
                        if(!StringUtils.isBlank(unqualifiedLossD.getLossQty())){
                            qty=qty.add(new BigDecimal(unqualifiedLossD.getLossQty()));
                        }
                    }
                }
                if(qty.compareTo(new BigDecimal(gspUnqualifiedLossD.getLossQty()))!=0){
                    throw new BizException("商品"+gspUnqualifiedLossD.getItemCode()+"报损数量不对，请核对");
                }
            }
            for (int i = 0; i < dtoDList.size(); i++) {
                GspUnqualifiedLossD gspUnqualifiedLossD = dtoDList.get(i);
                if(StringUtils.isBlank(gspUnqualifiedLossD.getLocatorId())){
                    throw new BizException("商品"+gspUnqualifiedLossD.getItemCode()+"请填写货位");
                }
                gspUnqualifiedLossD.setId(null);
                gspUnqualifiedLossD.setStatus(status);
            }
            dMapper.deleteByCriteria(crt);
            dMapper.saveBatch(dtoDList);
            dList=dtoDList;
        }else{
            dMapper.updateMapByCriteria(MapUtils.put("status", status).put("gmtModified", auditDate).getMap(), crt);
        }
        gspUnqualifiedLoss.setGspUnqualifiedLossDList(dList);
        if ("20".equals(status)) {
            saveDxi(gspUnqualifiedLoss);
            InvStockCheck check = new InvStockCheck();
            check.setLineBillIds(dList.stream().map(GspUnqualifiedLossD::getId).toArray(String[]::new));
            log.info("调用库存接口scrapStockCheck,入参为：" + JSON.toJSONString(check));
            RestMessage restMessage = inventoryClient.scrapStockCheck(check);
            log.info("调用库存接口scrapStockCheck,入参为：" + JSON.toJSONString(check) + "，返回为：" + JSON.toJSONString(restMessage));
            if (restMessage == null || !restMessage.isSuccess()) {
                throw new BizException("调用库存异常：" + restMessage.getMessage());
            }
            //回传erp
            syncStockToErp(dList);
        } else if ("30".equals(status)) {
            InvStockCancel invStockCancel = new InvStockCancel();
            String[] lienIds = dList.stream().map(GspUnqualifiedLossD::getId).toArray(String[]::new);
            invStockCancel.setLineBillIds(lienIds);
            log.info("调用库存接口scrapCancel,入参为：" + JSON.toJSONString(invStockCancel));
            RestMessage restMessage = inventoryClient.scrapCancel(invStockCancel);
            log.info("调用库存接口scrapCancel,入参为：" + JSON.toJSONString(invStockCancel) + "，返回为：" + JSON.toJSONString(restMessage));
            if (restMessage == null || !restMessage.isSuccess()) {
                throw new BizException("调用库存异常：" + restMessage.getMessage());
            }
        }
    }

    private void syncStockToErp(List<GspUnqualifiedLossD> dList) {
        List<WmsInvStockQtyQueryVO> res = new ArrayList<>();
        for (GspUnqualifiedLossD gspUnqualifiedLossD : dList) {
            WmsInvStockQtyQueryVO wmsInvStockQtyQueryVO = new WmsInvStockQtyQueryVO();
            BeanUtils.copyProperties(gspUnqualifiedLossD,wmsInvStockQtyQueryVO);
            res.add(wmsInvStockQtyQueryVO);
        }
        RestMessage<List<WmsInvStockQtyVO>> restRet = inventoryClient.getAvailableQuantityList(res);
        if (restRet != null && restRet.isSuccess() && restRet.getData() != null && restRet.getData().size() == res.size()) {
            Date date = new Date();
            for (WmsInvStockQtyVO datum : restRet.getData()) {
                if (StringUtils.isEmpty(erpInventoryCallbackUrl)) {
                    throw new BizException("损益结果回传ERP请求路径配置为空");
                }
                String url = erpInventoryCallbackUrl;
                log.info("调用ERP损益结果回传接口URL:{}", url);
                Map<String,Object> params = new HashMap<>();
                params.put("goodSn",datum.getItemId());
                params.put("fLot",datum.getBatchId());
                params.put("stockNum",datum.getQuantity());
                params.put("alterTime",date);
                params.put("beforeWNo", datum.getWarehouseAreaCategory());
                GspUnqualifiedLossD gspUnqualifiedLossD = dList.stream().filter(item -> datum.getItemId().equals(item.getItemId()) && datum.getBatchId().equals(item.getBatchId())).findFirst().orElse(null);
                params.put("alterRemark",gspUnqualifiedLossD == null ? null :gspUnqualifiedLossD.getUnqualifiedReason());
                log.info("调用ERP损益结果回传接口入参:{}", JSONUtil.toJsonStr(params));
                String result = HttpUtil.post(url, JSONObject.toJSONString(params));
                JSONObject parse = JSONObject.parseObject(result);
                log.info("调用ERP损益结果回传接口返回参数:{}",parse);
            }
        }
    }

    private void saveDxi(GspUnqualifiedLoss model) {
        List<GspUnqualifiedLossDVO> gspUnqualifiedLossDList = spellGspUnqualifiedLossDVOS(model.getGspUnqualifiedLossDList());
        List<OmsInventoryResultVO> resultListVO = new ArrayList<>();
        UserDTO userDTO = userTemplate.getUserDTO();
        BaseWmsWarehouseMst wmsWarehouseMst = null;
        List<InvStockScarp> invStockList = new ArrayList<>();
        for (int i = 0; i < gspUnqualifiedLossDList.size(); i++) {
            GspUnqualifiedLossDVO dDto = gspUnqualifiedLossDList.get(i);
            if (i == 0) {
                RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = warehouseClient.warehouse(dDto.getWarehouseId());
                if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
                    wmsWarehouseMst = itemResultWarehouse.getData();
                }
            }
            DxiGspGainslossesBillRec owsModel = new DxiGspGainslossesBillRec();
            owsModel.setLineid(dDto.getId());//对接单据行号
            owsModel.setSeqno(dDto.getSeqNo());//对接单据行号
            owsModel.setBillid(model.getId());//单据ID
            owsModel.setBillno(model.getCode());//单据编号
            owsModel.setType("1");//单据类型,长度只能为1
            owsModel.setStatus("1");//状态,长度只能为1
            owsModel.setConsignorid(dDto.getCargoOwnerId());//货主ID
            owsModel.setConsignorcode(dDto.getCargoOwnerCode());//货主编码
            owsModel.setConsignorname(dDto.getCargoOwnerName());//货主名称
            owsModel.setBranchid(model.getWarehouseId());//仓库ID
            if (wmsWarehouseMst != null) {
                owsModel.setBranchcode(wmsWarehouseMst.getWarehouseCode());//仓库编码
            }
            owsModel.setBranchname(model.getWarehouseName());//仓库名称
            owsModel.setItemid(dDto.getItemId());//商品ID
            owsModel.setItemname(dDto.getItemName());//商品名称
            owsModel.setItemcode(dDto.getItemCode());//商品编码
            //			owsModel.setPrice();//单价
            owsModel.setAmount(dDto.getLossQty());//数量
            //			owsModel.setPackAmount();//包装数量
            //			owsModel.setPackUnit();//包装单位
            //			owsModel.setTotalPrice();//总金额
            //			owsModel.setSpec();//规格
            //			owsModel.setPlace();//产地
            owsModel.setManufacturer(dDto.getManufacturerName());//生产企业
            owsModel.setProductionDate(dDto.getProductionDate());//生产日期
            owsModel.setExpiredDate(dDto.getExpiredDate());//有效期至
            if (StringUtils.isBlank(owsModel.getBatchNum())) {
                owsModel.setBatchNum(StringUtils.isBlank(dDto.getLotNum()) ? "N/A" : dDto.getLotNum());//批号
            }
            //			owsModel.setApprovalNumber();//批准文号
            if (StringUtils.isBlank(dDto.getOpinion())) {
                owsModel.setReason("N/A");
            } else {
                owsModel.setReason(dDto.getOpinion());//原因
            }
            //			owsModel.setRefBilltype();//数据来源
            //			owsModel.setAttrStr1();//扩展字段1
            //			owsModel.setAttrStr2();//扩展字段2
            //			owsModel.setAttrStr3();//扩展字段3
            //			owsModel.setAttrStr4();//扩展字段4
            //			owsModel.setAttrStr5();//扩展字段5
            //			owsModel.setAttrStr6();//扩展字段6
            //			owsModel.setAttrStr7();//扩展字段7
            //			owsModel.setAttrStr8();//扩展字段8
            //			owsModel.setAttrStr9();//扩展字段9
            //			owsModel.setAttrStr10();//扩展字段10
            //			owsModel.setAttrNum1();//扩展字段11
            //			owsModel.setAttrNum2();//扩展字段12
            //			owsModel.setAttrNum3();//扩展字段13
            //			owsModel.setAttrNum4();//扩展字段14
            //			owsModel.setAttrNum5();//扩展字段15
            //			owsModel.setAttrDte1();//扩展字段16
            //			owsModel.setAttrDte2();//扩展字段17
            //			owsModel.setAttrDte3();//扩展字段18
            //			owsModel.setAttrDte4();//扩展字段19
            //			owsModel.setAttrDte5();//扩展字段20
            owsModel.setCreatedate(model.getGmtCreate());//创建时间
            owsModel.setCreateby(model.getCreatorName());//创建人
            owsModel.setLastmodifydate(model.getGmtModified());//修改时间
            owsModel.setLastmodifyby(model.getCreatorName());//修改人
            owsModel.setEnterpriseid(userDTO.getEnterpriseId());//企业ID
            owsModel.setEnterprisename(userDTO.getEnterpriseName());//企业名称
            owsModel.setBilldate(model.getGmtCreate());
            dxiGspGainslossesBillRecMapper.save(owsModel);

            // 预占库存
            InvStockScarp invStockScarp = new InvStockScarp();
            invStockScarp.setBillId(model.getId());
            invStockScarp.setLineBillId(dDto.getId());
            invStockScarp.setWarehouseId(model.getWarehouseId());
            InvStockScrapDetail invStockScrapDetail = new InvStockScrapDetail();
            invStockScrapDetail.setBatchId(dDto.getBatchId());
            invStockScrapDetail.setLocatorId(dDto.getLocatorId());
            invStockScrapDetail.setQuantity(new BigDecimal(dDto.getLossQty()));
            invStockScarp.setDetails((new ArrayList<InvStockScrapDetail>() {{
                add(invStockScrapDetail);
            }}));
            invStockList.add(invStockScarp);

            //回传OMS 通过接口平台
            OmsInventoryResultVO resultVO = new OmsInventoryResultVO();
            resultVO.setBillno(owsModel.getBillno());
            resultVO.setBilldate(DateUtils.format(owsModel.getBilldate(),"yyyy-MM-dd HH:mm:ss"));
            resultVO.setInventoryby(userDTO.getUsername());
            resultVO.setSeqNo(owsModel.getSeqno());
            resultVO.setItemcode(owsModel.getItemcode());
            resultVO.setCausticQty(new BigDecimal(dDto.getUnqualifiedQty()));
            resultVO.setCausticReason(owsModel.getReason());
            resultVO.setLotNo(owsModel.getBatchNum());
            resultVO.setPdateFrom(DateUtils.format(owsModel.getProductionDate(),"yyyy-MM-dd HH:mm:ss"));
            resultVO.setValidUntil(DateUtils.format(owsModel.getExpiredDate(),"yyyy-MM-dd HH:mm:ss"));
            resultVO.setCausticType("3");
            resultVO.setQty(BigDecimal.ZERO);
            resultVO.setOperatorName(userDTO.getUsername());
            resultVO.setConfirmer(userDTO.getUsername());
            resultVO.setAuditDate(DateUtils.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
            resultVO.setUnqualifiedQty(new BigDecimal(dDto.getUnqualifiedQty()));
            resultVO.setUnqualifiedResource(dDto.getUnqualifiedReason());
            resultVO.setUnqualifiedSource("0");
            resultVO.setOpinion(dDto.getOpinion());
            resultVO.setConsignorcode(owsModel.getConsignorcode());
            resultVO.setBranchcode(owsModel.getBranchcode());
            resultVO.setPenterpriseid(owsModel.getEnterpriseid());
            resultVO.setItemid(owsModel.getItemid());
            resultListVO.add(resultVO);
        }
//        RestMessage upKeepDictResult = inventoryClient.scrapStock(invStockList);
//        log.info("调用库存接口scrapStock,入参为：" + JSON.toJSONString(invStockList) + "，返回为：" + JSON.toJSONString(upKeepDictResult));
//        if (upKeepDictResult == null || !upKeepDictResult.isSuccess()) {
//            throw new BizException("调用库存异常:" + upKeepDictResult.getMessage());
//        }

        try {
            //回传OMS
            RestMessage<?> msg = inventoryClient.askIntegration(new AskIntegrationVo("loss", resultListVO));
            log.info("调用OMS结果成功：{}", JSONObject.toJSONString(msg));
        }catch (Exception e){
            log.error("调用OMS结果失败", e);
        }
    }

    private void saveDxiOrder(GspUnqualifiedLoss model) {
        List<GspUnqualifiedLossDVO> gspUnqualifiedLossDList = spellGspUnqualifiedLossDVOS(model.getGspUnqualifiedLossDList());
        UserDTO userDTO = userTemplate.getUserDTO();
        BaseWmsWarehouseMst wmsWarehouseMst = null;
        List<OmsInventoryOrder> inoList = new ArrayList<>();
        Date now = new Date();
        for (int i = 0; i < gspUnqualifiedLossDList.size(); i++) {
            GspUnqualifiedLossDVO dDto = gspUnqualifiedLossDList.get(i);
            OmsInventoryOrder ino = new OmsInventoryOrder();
            ino.setBillid(model.getId());//单据ID
            ino.setBillno(model.getCode());//单据编号
            ino.setBilldate(now);
            ino.setType("3");
            ino.setAmount(new BigDecimal(dDto.getLossQty()));
            // 设置批次相关数据
            ino.setAttrStr2(dDto.getBatchProductionDateShow()); // 显示生产日期
            ino.setAttrStr3(dDto.getBatchExpiredDateShow()); // 显示有效期至
            ino.setBatchNum(dDto.getLotNum()); // 批号
            ino.setProductionDate(dDto.getProductionDate());
            ino.setExpiredDate(dDto.getExpiredDate());
            // 设置仓库相关数据
            if (i == 0) {
                RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = warehouseClient.warehouse(dDto.getWarehouseId());
                if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
                    wmsWarehouseMst = itemResultWarehouse.getData();
                }
            }
            ino.setBranchid(wmsWarehouseMst.getWarehouseId()); // 仓库id
            ino.setBranchcode(wmsWarehouseMst.getWarehouseCode());
            ino.setBranchname(wmsWarehouseMst.getWarehouseName()); // 仓库名称
            // 还需要建筑物
            //			String bldgName = dDto.getBldgName();
            //			ino.setBuilding(dDto.get);
            // 设置货主相关
            ino.setConsignorid(dDto.getCargoOwnerId());
            ino.setConsignorcode(dDto.getCargoOwnerCode());
            ino.setConsignorname(dDto.getCargoOwnerName());
            // 设置商品相关
            ino.setItemid(dDto.getItemId());
            ino.setItemcode(dDto.getItemCode());
            ino.setItemname(dDto.getItemName());
            ino.setApprovalNumber(dDto.getItemHealthApprovalNbr());
            //ino.setPrice(dDto.getPiecePurchasePriceTi());
            ino.setSpec(dDto.getSpecification());
            ino.setPlace(dDto.getCountryOriginName());
            ino.setManufacturer(dDto.getManufacturerName());
            ino.setLineid(dDto.getId());
            //			BigDecimal price = dDto.getPrice();
            //			if (price != null) {
            //				ino.setTotalPrice(price.multiply(wmsAdjustD.getPieceQuantity().abs()));
            //			}
            ino.setPackUnit(dDto.getCaseUom());
            ino.setPackAmount(dDto.getCaseConversionRate());
            ino.setStockstatus("202");//不合格
            ino.setStatus("10"); // 初始状态创建中
            ino.setDatasource("1"); // 来源wms
            //			ino.setRemark(dDto.getComments());
            //			ino.setBasenum(dDto.getPieceAccount());
            //			ino.setExecnum(dDto.getPieceAccountFact());
            //			Long lineNum = wmsAdjustD.getLineNum();
            ino.setSeqno(dDto.getSeqNo());
            ino.setEnterpriseid(userDTO.getEnterpriseId());
            ino.setEnterprisename(userDTO.getEnterpriseName());
            ino.setSalemanid(userDTO.getId());
            ino.setCaozyid(userDTO.getId());
            ino.setCreatedate(now);
            ino.setCreateby(userDTO.getUsername());
            ino.setLastmodifydate(now);
            ino.setLastmodifyby(userDTO.getUsername());
            ino.setIsDestroy("N"); // 默认不销毁
            inoList.add(ino);
        }
        long saveBatch = omsInventoryOrderMapper.saveBatch(inoList);
    }

    /**
     * 是否需要先提交Erp审核
     *
     * @param warehouseId
     * @param cargoOwnerId
     * @param enterpriseId
     * @return
     */
    public Boolean isNeedErpAudit(String warehouseId, String cargoOwnerId, String enterpriseId) {
        Boolean returnVal = true;// 默认审核

        // 开启erp审核的值
        String onVal = "0";
        RestMessage<BusinessControl> res = strategyClient.registryByCode(this.erpAuditRegCode, warehouseId, cargoOwnerId, enterpriseId);

        if (res.isSuccess() && ObjectUtils.isNotNull(res.getData())) {
            BusinessControl data = res.getData();
            if (!StringUtils.isBlank(data.getRegValue()) && data.getRegValue().equals(onVal)) {
                returnVal = false;
            }
        }

        return returnVal;
    }

    @Override
    public Boolean erpAdd(ErpUnqualifiedLossVo vo) {
        if (CollUtil.isEmpty(vo.getData().getBills())){
            throw new BizException("单据为空");
        }
        for (ErpUnqualifiedLossVo.LossH bill : vo.getData().getBills()) {
            BaseWmsWarehouseMst wmsWarehouseMst = null;
            RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = warehouseClient.warehouse(bill.getBranchid());
            if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
                wmsWarehouseMst = itemResultWarehouse.getData();
            }
            if (wmsWarehouseMst == null) {
                throw new ParameterException("仓库不能为空");
            }
            if (CollUtil.isEmpty(bill.getDetails())){
                throw new BizException("单号【" + bill.getBillno() + "】的明细为空！");
            }
            GspUnqualifiedLoss model = new GspUnqualifiedLoss();
            model.setCreator("ERP");
            String id = String.valueOf(SnowFlakeUtils.getId());
            model.setId(id);
            String code = "BSD" + id.substring(id.length() - 8);
            model.setCode(code);
            model.setCreatorName("ERP");
            model.setGmtCreate(DateUtil.date());
            model.setModifier("ERP");
            model.setModifierName("ERP");
            model.setGmtModified(DateUtil.date());
            model.setEnterpriseId(bill.getEnterpriseid());
            model.setStatus("10");
            model.setDcId(wmsWarehouseMst.getDcId());
            model.setSource("ERP");
            int i = 1;
            List<InvStockScarp> invStockList = new ArrayList<>();
            for (ErpUnqualifiedLossVo.LossD detail : bill.getDetails()) {
                GspUnqualifiedLossD dModel = new GspUnqualifiedLossD();
                String unqualifiedQty = detail.getQty();
                String lossQty = dModel.getLossQty();
                if ((StringUtils.isBlank(unqualifiedQty) || StringUtils.isBlank(lossQty)) ||
                        (new BigDecimal(unqualifiedQty)).compareTo(new BigDecimal(lossQty)) < 0) {
                    throw new BizException("报损数量不能大于不合格数量：第" + (i + 1) + "行");
                }
                String sonId = String.valueOf(SnowFlakeUtils.getId());
                dModel.setId(sonId);
                dModel.setDcId(wmsWarehouseMst.getDcId());
                dModel.setWarehouseId(model.getWarehouseId());
                dModel.setEnterpriseId(bill.getEnterpriseid());
                dModel.setLossId(id);
                dModel.setLossCode(code);
                if (StringUtils.isBlank(dModel.getLotNum()) && !StringUtils.isBlank(dModel.getManufacturerLotNum())) {
                    dModel.setLotNum(dModel.getManufacturerLotNum());
                }
                dModel.setStatus("10");
                dModel.setDestroyingQty("0");
                dModel.setDestroyedQty("0");
                dModel.setCreator("ERP");
                dModel.setCreatorName("ERP");
                dModel.setGmtCreate(DateUtil.date());
                dModel.setModifier("ERP");
                dModel.setModifierName("ERP");
                dModel.setGmtModified(DateUtil.date());
                dModel.setSeqNo(Integer.toString((i + 1)));//对接单据行号
                dMapper.save(dModel);
                //生成预占
                InvStockScarp invStockScarp=new InvStockScarp();
                invStockScarp.setBillId(id);
                invStockScarp.setLineBillId(sonId);
                invStockScarp.setWarehouseId(model.getWarehouseId());
                InvStockScrapDetail invStockScrapDetail=new InvStockScrapDetail();
                invStockScrapDetail.setBatchId(dModel.getBatchId());
                invStockScrapDetail.setLocatorId(dModel.getLocatorId());
                invStockScrapDetail.setQuantity(new BigDecimal(dModel.getLossQty()));
                invStockScarp.setDetails((new ArrayList<InvStockScrapDetail>(){{add(invStockScrapDetail);}}));
                invStockList.add(invStockScarp);
                i ++;
            }
            RestMessage upKeepDictResult = inventoryClient.scrapStock(invStockList);
            log.info("调用库存接口scrapStock,入参为："+ JSON.toJSONString(invStockList)+"，返回为："+JSON.toJSONString(upKeepDictResult));
            if (upKeepDictResult==null || !upKeepDictResult.isSuccess()) {
                throw new BizException("调用库存异常:"+ (upKeepDictResult == null?"返回结果为null":upKeepDictResult.getMessage()));
            }

            //ERP下发自动审核通过
            try {
                this.oneAudit(model, "20", DateUtil.date());
            }catch (Exception e){
                log.error("库存处理异常！", e);
            }
        }
        return true;
    }
}
