chengsc
2025-03-17 7642a3e183b5a584d1da5eb6b48e0f9cb2b5c68c
Wms/WMS.BLL/BllSoServer/ExportNoticeServer.cs
@@ -26,12 +26,16 @@
using System.Runtime.Intrinsics.X86;
using ZXing.OneD;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using Model.ModelDto.LogDto;
namespace WMS.BLL.BllSoServer
{
    public class ExportNoticeServer : DbHelper<BllExportNotice>, IExportNoticeServer
    {
        private static readonly SqlSugarScope Db = DataContext.Db;
        private readonly object IssueOutLock = new object();
        public ExportNoticeServer() : base(Db)
        {
        }
@@ -812,6 +816,8 @@
        #endregion
        #region JC34
        #region 基础功能
        public async Task<List<ExportNoticeDto>> GetExportNoticeList(GetExportNoticeVm model, RefAsync<int> count)
@@ -839,12 +845,14 @@
                .LeftJoin<SysUserInfor>((a, b, c) => a.CreateUser == c.Id)
                .LeftJoin<SysUserInfor>((a, b, c, d) => a.CreateUser == d.Id)
                .LeftJoin<SysUserInfor>((a, b, c, d, e) => a.CheckUser == e.Id)
                .Select((a, b, c, d, e) => new ExportNoticeDto()
                .LeftJoin<SysWareHouse>((a, b, c, d, e,f) => a.WareHouseNo == f.WareHouseNo)
                .Select((a, b, c, d, e,f) => new ExportNoticeDto()
                {
                    Id = a.Id,
                    SONo = a.SONo,
                    Type = a.Type,
                    Status = a.Status,
                    WareHouseName = f.WareHouseName,
                    Origin = a.Origin,
                    CustomerNo = a.CustomerNo,
                    CustomerName = a.CustomerName,
@@ -873,10 +881,14 @@
        }
        //获取添加/编辑出库单时选择物料明细信息
        public List<ExStockInfoDto> GetStockGroupList(string type, string ownerNo, string msg)
        public List<ExStockInfoDto> GetStockGroupList(string house, string type, string ownerNo, string msg)
        {
            try
            {
                if (string.IsNullOrEmpty(house))
                {
                    throw new Exception("请选择出库仓库");
                }
                if (string.IsNullOrEmpty(type))
                {
                    throw new Exception("请选择出库单类型");
@@ -893,23 +905,52 @@
                switch (type)//0:原料 1:包材 2:成品 3:耗材 4:半成品
                {
                    case "0"://成品出库
                        if (house !="W01")
                        {
                            throw new Exception("成品出库只能选择成品库");
                        }
                        skuType = "(2)";
                        inspectStatus = "1";
                        break;
                    case "1"://领料出库
                        if (house != "W02")
                        {
                            throw new Exception("领料出库只能选择原料库");
                        }
                        skuType = "(0,1,3)";
                        inspectStatus = "1";
                        break;
                    case "2"://抽检出库
                        skuType = "(0,1,2,3)";
                        if (house == "W01")
                        {
                            skuType = "(2)";
                        }
                        if (house == "W02")
                        {
                            skuType = "(0,1,3)";
                        }
                        inspectStatus = "0,1,2";
                        break;
                    case "3"://物料取样出库
                        skuType = "(0,1,2,3)";
                        if (house == "W01")
                        {
                            skuType = "(2)";
                        }
                        if (house == "W02")
                        {
                            skuType = "(0,1,3)";
                        }
                        inspectStatus = "0";
                        break;
                    case "4"://不合格品出库
                        skuType = "(0,1,2,3)";
                        if (house == "W01")
                        {
                            skuType = "(2)";
                        }
                        if (house == "W02")
                        {
                            skuType = "(0,1,3)";
                        }
                        inspectStatus = "2";
                        break;
                    case "5"://中间品出库
@@ -920,14 +961,38 @@
                        skuType = "(2)";
                        inspectStatus = "0,1";
                        break;
                    case "8"://寄存出库
                        skuType = "(0,1,2,3)";
                    case "7"://其它出库
                        if (house == "W01")
                        {
                            skuType = "(2)";
                        }
                        if (house == "W02")
                        {
                            skuType = "(0,1,3,4)";
                        }
                        inspectStatus = "0,1";
                        break;
                    case "8"://寄存出库
                        if (house == "W01")
                        {
                            skuType = "(2)";
                        }
                        if (house == "W02")
                        {
                            skuType = "(0,1,3)";
                        }
                        inspectStatus = "0,1";
                        break;
                    case "9"://生产领料出库
                        if (house != "W02")
                        {
                            throw new Exception("生产领料出库只能选择原料库");
                        }
                        skuType = "(0,1,3)";
                        inspectStatus = "1";
                        break;
                    default: //其它出库
                        skuType = "(0,1,2,3,4)";
                        inspectStatus = "0,1";
                        break;
                        throw new Exception("单据类型错误");
                }
                var skuList = sku.Where(m => skuType.Contains(m.Type)).ToList();
                if (skuList.Count == 0)
@@ -937,9 +1002,9 @@
                if (type == "6")
                {
                    skuList = skuList.Where(m=> string.IsNullOrWhiteSpace(m.PackagNo)).ToList();
                    skuList = skuList.Where(m => string.IsNullOrWhiteSpace(m.PackagNo)).ToList();
                }
                if (type!="8")
                if (type != "8")
                {
                    skuList = skuList.Where(m => m.SkuNo != "100088").ToList();
                }
@@ -951,7 +1016,7 @@
                var stockRst = new StockServer();
                var stockDetailRst = new StockDetailServer();
                Expression<Func<DataStockDetail, bool>> item = Expressionable.Create<DataStockDetail>()
                    //.And(it => it.WareHouseNo == wareHouseNo)
                    .And(it => it.WareHouseNo == house)
                    .AndIF(!string.IsNullOrWhiteSpace(inspectStatus), it => inspectStatus.Contains(it.InspectStatus))
                    .And(m => skuStrList.Contains(m.SkuNo))
                    .AndIF(type == "6", m => m.OwnerNo == ownerNo)//代储出库需要关联货主
@@ -1035,6 +1100,23 @@
                var skuNos = model.Detail.Select(a => a.SkuNo).Distinct().ToList();
                //根据物料号获取物料信息、库存明细中获取批次描述供货批次等
                var skuList = Db.Queryable<SysMaterials>().Where(a => skuNos.Contains(a.SkuNo) && a.IsDel == "0").ToList();
                switch (model.WareHouseNo)
                {
                    case "W01"://成品库
                        if (skuList.Any(m=>m.Type !="2"))
                        {
                            throw new Exception("仓库与出库物料不符");
                        }
                        break;
                    case "W02"://原料库
                        if (skuList.Any(m => m.Type == "2"))
                        {
                            throw new Exception("仓库与出库物料不符");
                        }
                        break;
                    default:
                        throw new Exception("仓库号错误");
                }
                var stockList = Db.Queryable<DataStock>().Where(s => skuNos.Contains(s.SkuNo) && (s.Qty - s.FrozenQty - s.LockQty) > 0).ToList();
                //var palletList = contextDb.Queryable<DataStockDetail>().Where(s => skuNos.Contains(s.SkuNo) && (s.Qty - s.FrozenQty - s.LockQty) > 0).ToList();
                //客户信息
@@ -1068,7 +1150,7 @@
                            throw new Exception($"物料信息中未查询到出库物料信息:{d.SkuNo}");
                        }
                        //0:成品出库、1:领料出库、2:抽检出库、4:不合格品出库、6:代储出库、7:其他出库、 ///3:物料取样出库、5:中间品出库、8:寄存出库
                        //0:成品出库、1:领料出库、2:抽检出库、4:不合格品出库、7:其他出库、9生产领料出库 ///3:物料取样出库、5:中间品出库、6:代储出库、8:寄存出库
                        if (model.Type == "0" || model.Type == "2" || model.Type == "4" || model.Type == "7")
                        {
                            if (string.IsNullOrWhiteSpace(d.LotNo))
@@ -1077,20 +1159,20 @@
                            }
                        }
                        if (model.Type == "1")
                        {
                            if (list.Count(m=>m.SkuNo == d.SkuNo)>=2)
                            {
                                throw new Exception("领料出库单同单据同物料不允许超过3个批次混批出库");
                            }
                        }
                        else
                        {
                            if (list.Count(m => m.SkuNo == d.SkuNo) >= 1)
                            {
                                throw new Exception("出库单同单据同物料不允许超过2个批次混批出库");
                            }
                        }
                        //if (model.Type == "1")
                        //{
                        //    if (list.Count(m=>m.SkuNo == d.SkuNo)>=2)
                        //    {
                        //        throw new Exception("领料出库单同单据同物料不允许超过3个批次混批出库");
                        //    }
                        //}
                        //else
                        //{
                        //    if (list.Count(m => m.SkuNo == d.SkuNo) >= 1)
                        //    {
                        //        throw new Exception("出库单同单据同物料不允许超过2个批次混批出库");
                        //    }
                        //}
                        //库存
                        List<DataStock> stocks;
@@ -1141,7 +1223,7 @@
                        };
                        list.Add(item);
                        stocks.First().LockQty += d.Qty;//锁定数量
                        var i = Db.Updateable(stocks.First()).UpdateColumns(it => new { it.LockQty })
                            .ExecuteCommand();
@@ -1218,6 +1300,7 @@
                {
                    SoNo = notify.SONo,
                    Type = notify.Type,
                    WareHouseNo = notify.WareHouseNo,
                    CustomerNo = notify.CustomerNo,
                    LogisticsId = notify.LogisticsId,
                    //ExportWarehouseId = notify.ExportWarehouseId,
@@ -1618,10 +1701,10 @@
                    //查询改后的单据信息 后期接口对接完后需改动回传参数
                    var detail = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == notice.SONo).Select(m => new SelectStockSkuDto
                    {
                        LotNo =m.LotNo,
                        LotNo = m.LotNo,
                        SkuNo = m.SkuNo,
                        SkuName = m.SkuName,
                        Qty = m.Qty,
                        Qty = m.Qty,
                        ExQty = decimal.Parse(m.CompleteQty.ToString()),
                        Standard = m.Standard,
                        IsBale = m.IsBale,
@@ -2154,6 +2237,1887 @@
        }
        #endregion
        #region 自动分配、取消分配、获取手动分配的数据源、手动分配
        // 判断是否是跨批出库
        public bool IsCrossLotNo(string soNo)
        {
            try
            {
                //方法返回结果:bl
                var bl = true;
                //查询单据信息
                var notice = Db.Queryable<BllExportNotice>().First(m => m.SONo == soNo && m.IsDel == "0");
                //判断单据类型  成品出库、领料出库(其它类型跳出此方法)
                if (notice.Type != "0" && notice.Type != "1")
                {
                    return bl;
                }
                //查询到当前单据下的出库单明细信息
                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList();
                //库存总表信息
                var data = Db.Queryable<DataStock>().Where(m => m.IsDel == "0").ToList();
                //库存明细中检验合格批次集合
                var dataDetail = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.InspectStatus == "1").GroupBy(g => g.LotNo).Select(s => s.LotNo).ToList();
                //库存明细表信息
                var dataBoxInfo = Db.Queryable<DataBoxInfo>().Where(m => m.IsDel == "0").ToList();
                //循环单据明细信息
                foreach (var item in noticeDetail)
                {
                    //验证先进先出原则
                    //获取当前物料的所有批次信息(排除单据的批次,防止单据所在批次锁定数量后验证小于等于0)
                    var forData = data.Where(m => m.SkuNo == item.SkuNo
                    && m.LotNo != item.LotNo && (m.Qty - m.FrozenQty - m.LockQty) > 0
                    && dataDetail.Contains(m.LotNo)).Select(m => m.LotNo).ToList();
                    forData.Add(item.LotNo);  //集合添加单据的批次
                    //获取排序后的第一个批次
                    var firstLotNo = forData.OrderBy(m => m).First();
                    if (firstLotNo != item.LotNo)
                    {
                        bl = false;
                        break;
                    }
                    //验证效期优先原则
                    var forDataBox = dataBoxInfo.Where(m => m.SkuNo == item.SkuNo && m.LotNo != item.LotNo && m.Qty > 0).ToList();
                    //获取当前单据批次的最近效期
                    var expirationTimedt = dataBoxInfo.Where(m => m.SkuNo == item.SkuNo
                    && m.LotNo == item.LotNo && m.Qty > 0).ToList();
                    if (expirationTimedt.Count > 0)
                    {
                        var expirationTime = expirationTimedt.OrderBy(m => m.ExpirationTime).Select(m => m.ExpirationTime).First();
                        //获取库存中其它批次效期大于当前单据批次的效期数量
                        var num = forDataBox.Count(m => m.ExpirationTime > expirationTime);
                        //判断是否大于0
                        if (num > 0)
                        {
                            bl = false;
                            break;
                        }
                    }
                    else
                    {
                        var dataDetailtime = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.InspectStatus == "1").
                            Where(m => m.SkuNo == item.SkuNo
                            && m.LotNo == item.LotNo && m.Qty > 0)
                            .OrderBy(m => m.ExpirationTime)
                            .Select(m => m.ExpirationTime).First();
                        var num = forDataBox.Count(m => m.ExpirationTime > dataDetailtime);
                        //判断是否大于0
                        if (num > 0)
                        {
                            bl = false;
                            break;
                        }
                    }
                }
                return bl;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        /// <summary>
        /// 自动分配
        /// </summary>
        /// <param name="soNo"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool AutoAllot(string soNo, int userId)
        {
            try
            {
                #region 判断条件(出库单、出库单明细)
                //出库单
                var notice = Db.Queryable<BllExportNotice>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList().FirstOrDefault();
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                if (notice.Status != "0" && notice.Status != "1")
                {
                    throw new Exception("参数异常,请检查状态是否为等待执行或部分分配;");
                }
                //出库单明细
                var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == soNo && (m.AllotQty - m.Qty) <= 0).ToList();
                if (!detailList.Any())
                {
                    throw new Exception("未查询到符合分配条件的出库单据明细信息");
                }
                #endregion
                var exAllotList = new List<BllExportAllot>();
                var assign = new AllotSku();
                Db.BeginTran();
                try
                {
                    List<SoDetailInfo> soDetailList = new List<SoDetailInfo>();
                    foreach (var detail in detailList)
                    {
                        if (detail.AllotQty >= detail.Qty)
                        {
                            continue;
                        }
                        //还需要分配的数量
                        decimal needQty = detail.Qty - (detail.AllotQty == null ? 0 : decimal.Parse(detail.AllotQty.ToString()));
                        //库存明细 Status 0:待分配 1:部分分配  2:已分配
                        var stockDetail = Db.Queryable<DataStockDetail>().Where(m => m.SkuNo == detail.SkuNo && (m.Qty - m.FrozenQty - m.LockQty + m.InspectQty) > 0 && (m.Status == "0" || m.Status == "1") && m.IsDel == "0").ToList();
                        //判断单号是否指定批次
                        if (!string.IsNullOrWhiteSpace(detail.LotNo))
                        {
                            stockDetail = stockDetail.Where(m => m.SkuNo == detail.SkuNo && m.LotNo == detail.LotNo && m.IsDel == "0").ToList();
                        }
                        else
                        {
                            stockDetail = stockDetail.Where(m => m.SkuNo == detail.SkuNo && m.IsDel == "0" && string.IsNullOrWhiteSpace(m.LotNo)).ToList();
                        }
                        if (stockDetail.Count < 1)
                        {
                            throw new Exception("库存不足,无可出库库存");
                        }
                        //0:成品出库、1:领料出库、2:抽检出库、4:不合格品出库、7:其他出库、9:生产领料出库 ///3:取样出库、5:中间品出库、8:寄存出库
                        if (notice.Type == "0" || notice.Type == "1" || notice.Type == "9")//成品、领料出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "1").ToList();
                        }
                        else if (notice.Type == "2")//抽检出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "0" || m.InspectStatus == "1" || m.InspectStatus == "2").ToList();
                        }
                        else if (notice.Type == "4")//不合格出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "2").ToList();
                        }
                        else if (notice.Type == "7") //、其它
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "0" || m.InspectStatus == "1").ToList();
                        }
                        if (stockDetail.Sum(m => m.Qty - m.LockQty) < needQty)
                        {
                            throw new Exception("库存明细数量不足");
                        }
                        #region 包装信息
                        var pNum = 0;//托盘物品数量
                        var bNum = 0;//箱物品数量
                        //公共方法获取包装数量
                        new Common().GetPackQtyInfo(detail.PackagNo, ref pNum, ref bNum);
                        #endregion
                        //取合适库存商品
                        Dictionary<int, decimal> stockQtyDic = new Dictionary<int, decimal>();//托出库物品数
                        var qty = 0m;
                        var house = "";
                        //分配货物
                        qty += assign.AllotPallets(stockDetail, needQty, pNum, bNum, stockQtyDic, notice.WareHouseNo);
                        foreach (var sc in stockQtyDic)
                        {
                            var s = stockDetail.FirstOrDefault(m => m.Id == sc.Key);
                            //添加分配表信息
                            var allot = new BllExportAllot
                            {
                                SONo = notice.SONo,
                                WaveNo = "",
                                SODetailNo = detail.Id,
                                StockId = sc.Key,
                                LotNo = s.LotNo,
                                LotText = s.LotText,
                                SupplierLot = s.SupplierLot,
                                SkuNo = s.SkuNo,
                                SkuName = s.SkuName,
                                Standard = s.Standard,
                                PalletNo = s.PalletNo,
                                IsBale = detail.IsBale == "0" ? "0" : s.IsBale == "1" ? "0" : "1", //是否裹包
                                IsBelt = detail.IsBelt == "0" ? "0" : s.IsBelt == "1" ? "0" : "1", //是否打带
                                Qty = sc.Value,
                                CompleteQty = 0,
                                //BoxexQty = s.Qty, //箱内数量
                                Status = "0",
                                LogisticsId = notice.LogisticsId,
                                IsAdvance = "0",
                                OutMode = "",//出库口
                                CreateUser = userId,
                                CreateTime = DateTime.Now
                            };
                            exAllotList.Add(allot);
                            s.LockQty += stockQtyDic[s.Id];
                            if (s.LockQty == s.Qty)
                            {
                                s.Status = "2";
                            }
                            else
                            {
                                s.Status = "1";
                            }
                            var sd = Db.Updateable(s).UpdateColumns(it => new { it.LockQty, it.Status }).ExecuteCommand();
                        }
                        detail.AllotQty += qty;
                        detail.UpdateUser = userId;
                        detail.UpdateTime = DateTime.Now;
                        if (detail.Status == "0")
                        {
                            detail.Status = "1";
                        }
                        if (qty > detail.Qty)
                        {
                            //库存总表
                            var stock = Db.Queryable<DataStock>().First(d => d.IsDel == "0"
                            && d.SkuNo == detail.SkuNo
                            && d.LotNo == detail.LotNo);
                            stock.LockQty += qty - detail.Qty;
                            Db.Updateable(stock).ExecuteCommand();
                            //添加回传上游系统锁定数量更改代码
                            SoDetailInfo soDetail = new SoDetailInfo();
                            soDetail.OrderDetailCode = detail.OrderDetailCode;
                            soDetail.LockQty = qty - detail.Qty;
                            soDetail.LotNo = detail.LotNo;
                            soDetailList.Add(soDetail);
                        }
                    }
                    var mx = Db.Updateable(detailList).ExecuteCommand();
                    var fp = Db.Insertable(exAllotList).ExecuteCommand();
                    //修改分配单据的状态
                    if (notice.Status == "0" || notice.Status == "1")
                    {
                        var bl = 0;
                        var bl2 = 0;
                        foreach (var item in detailList)
                        {
                            if (item.AllotQty <= 0)
                            {
                                continue;
                            }
                            if (item.AllotQty < item.Qty)
                            {
                                bl = 1;
                            }
                            else
                            {
                                bl2 = 1;
                            }
                        }
                        switch (bl2)
                        {
                            case 1 when bl == 1:
                                notice.Status = "1";//证明部分分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 0 when bl == 1:
                                notice.Status = "1";//证明部分分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 1 when bl == 0:
                                notice.Status = "2";//证明分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 0 when bl == 0:
                                //证明所有分配数量全部小于等于出库数量 不做修改
                                break;
                        }
                    }
                    notice.UpdateUser = userId;
                    notice.UpdateTime = DateTime.Now;
                    var zd = Db.Updateable(notice).ExecuteCommand();
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据",
                        notice.SONo, "分配", $"自动分配了单据号为{notice.SONo}的单据信息", userId);
                    if (zd > 0 && mx > 0 && fp > 0 && k)
                    {
                        #region 通过接口发送至erp
                        //系统对接后放开
                        /*var jsonData = JsonConvert.SerializeObject(soDetailList);
                        var response = HttpHelper.DoPost(url, jsonData, "库存锁定数量变更", "ERP");
                        var obj = JsonConvert.DeserializeObject<ErpModel>(response);//解析返回数据
                        if (obj.Success != 0)
                        {
                            throw new Exception("上传失败" + obj.Message);
                        }*/
                        #endregion
                        Db.CommitTran();
                        return true;
                    }
                    Db.RollbackTran();
                    return false;
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
            }
            catch (Exception e)
            {
                throw new Exception("自动分配失败:" + e.Message);
            }
        }
        //取消分配
        public bool CancelAllot(string soNo, int userId)
        {
            try
            {
                var notice = Db.Queryable<BllExportNotice>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList().FirstOrDefault();
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                if (notice.Status != "1" && notice.Status != "2")
                {
                    throw new Exception("参数异常,请检查状态是否为已分配或部分分配或来源是否是WMS");
                }
                //该单据的分配信息 Status 0:任务下发 1:待拣货 2:部分拣货 3:待回库 4:已完成
                var allotList = Db.Queryable<BllExportAllot>().Where(o => o.IsDel == "0" && o.SONo == soNo).ToList();
                //有已执行的分配数据不能取消
                if (allotList.Any(o => o.Status != "0"))
                {
                    throw new Exception("当前单据的分配信息已有执行中,不能取消分配");
                }
                List<SoDetailInfo> soDetailList = new List<SoDetailInfo>();
                //开启事务
                Db.BeginTran();
                try
                {
                    //查询分配的明细
                    var detail = Db.Queryable<BllExportNoticeDetail>().Where(d => d.SONo == soNo && d.AllotQty > 0 && d.IsDel == "0").ToList();
                    foreach (var d in detail)
                    {
                        var orders = allotList.Where(o => o.SODetailNo == d.Id).ToList();
                        foreach (var o in orders)
                        {
                            var pq = Db.Queryable<DataStockDetail>().Where(t => t.Id == o.StockId);
                            var pq2 = !string.IsNullOrWhiteSpace(o.LotNo) ? pq.Where(t => t.LotNo == o.LotNo).ToList() : pq.Where(t => string.IsNullOrWhiteSpace(t.LotNo)).ToList();
                            var pallet = pq2.FirstOrDefault();
                            if (pallet != null)
                            {
                                pallet.LockQty -= o.Qty;
                                pallet.Status = pallet.LockQty == 0 ? "0" : "1"; //如果锁定数量是0状态变更为待分配 否则为部分分配
                                Db.Updateable(pallet).ExecuteCommand();
                                //库存总表
                                //var stock = Db.Queryable<DataStock>().First(t => t.SkuNo == pallet.SkuNo && t.IsDel == "0");
                                //stock.LockQty -= o.Qty;
                                //Db.Updateable(stock).ExecuteCommand();
                            }
                        }
                        Db.Deleteable<BllExportAllot>(orders).ExecuteCommand();
                        if (d.AllotQty > d.Qty)
                        {
                            //库存总表
                            var stock = Db.Queryable<DataStock>().First(m => m.IsDel == "0" && m.SkuNo == d.SkuNo && m.LotNo == d.LotNo);
                            stock.LockQty -= (decimal)d.AllotQty - d.Qty;
                            Db.Updateable(stock).ExecuteCommand();
                            //添加回传上游系统锁定数量更改代码
                            SoDetailInfo soDetail = new SoDetailInfo();
                            soDetail.OrderDetailCode = d.OrderDetailCode;
                            soDetail.LockQty = (decimal)(d.Qty - d.AllotQty);
                            soDetail.LotNo = d.LotNo;
                            soDetailList.Add(soDetail);
                        }
                        d.AllotQty = 0;
                        d.Status = "0";
                        d.UpdateUser = userId;
                        d.UpdateTime = DateTime.Now;
                        //if (notice.Type == "1" || notice.Type == "5" || notice.Type == "6" || notice.Type == "7" || notice.Type == "8")//1:领料出库、
                        //{
                        //    if (d.IsIssueLotNo != "1")
                        //    {
                        //        d.LotNo = "";
                        //    }
                        //}
                    }
                    //查询当前单据是否已添加备料任务
                    if (notice.Type == "1")
                    {
                        var task = Db.Queryable<BllExportTimingTask>().First(m => m.IsDel == "0" && m.SoNo == soNo);
                        if (task != null)
                        {
                            task.IsDel = "1";
                            task.UpdateUser = userId;
                            task.UpdateTime = DateTime.Now;
                            Db.Updateable(task).ExecuteCommand();
                        }
                    }
                    notice.Status = "0";
                    notice.UpdateUser = userId;
                    notice.UpdateTime = DateTime.Now;
                    Db.Updateable(detail).ExecuteCommand();
                    Db.Updateable(notice).ExecuteCommand();
                    //系统对接后放开
                    /*var jsonData = JsonConvert.SerializeObject(soDetailList);
                    var response = HttpHelper.DoPost(url, jsonData, "库存锁定数量变更", "ERP");
                    var obj = JsonConvert.DeserializeObject<ErpModel>(response);//解析返回数据
                    if (obj.Success != 0)
                    {
                        throw new Exception("上传失败" + obj.Message);
                    }*/
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "取消分配", $"取消分配了单据号为{notice.SONo}的单据信息", userId);
                    Db.CommitTran();
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
                return true;
            }
            catch (Exception e)
            {
                throw new Exception("取消分配失败" + e.Message);
            }
        }
        /// <summary>
        /// 维护出库单备注信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="demo"></param>
        /// <param name="userId"></param>
        public void EditNoticeDemo(int id, string demo, int userId)
        {
            try
            {
                var notice = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.Id == id);
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                notice.Demo = demo + "".Trim();
                notice.UpdateUser = userId;
                notice.UpdateTime = DateTime.Now;
                int i = Db.Updateable(notice).ExecuteCommand();
                if (i > 0)
                {
                    //添加操作日志
                    new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "编辑", $"编辑了单据号为{notice.SONo}的备注信息", userId);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        //获取库存明细信息(出库单手动分配选择数据源)
        public List<StockDetailDto> GetHandOutList(int detailId, string houseNo, string roadwayNo, string locateNo, string msg, string palletNo)
        {
            try
            {
                var detail = Db.Queryable<BllExportNoticeDetail>().First(d => d.Id == detailId);
                #region 判断条件
                if (detail == null)
                {
                    throw new Exception("获取失败,未找到指定出库单!");
                }
                if (detail.Status != "0" && detail.Status != "1" && detail.AllotQty >= detail.Qty)
                {
                    throw new Exception("获取失败,出库单状态不是等待执行或分配中!");
                }
                if (detail.AllotQty >= detail.Qty)
                {
                    throw new Exception("获取失败,出库单已分配完成!");
                }
                var notice = Db.Queryable<BllExportNotice>().First(a => a.SONo == detail.SONo);
                if (notice == null)
                {
                    throw new Exception("获取失败,未找到指定出库单!");
                }
                if (notice.Status == "3" && detail.AllotQty >= detail.Qty || notice.Status == "4" || notice.Status == "5")
                {
                    throw new Exception("获取失败,出库单状态不允许!");
                }
                #endregion
                Expression<Func<DataStockDetail, bool>> item = Expressionable.Create<DataStockDetail>()
                    .AndIF(!string.IsNullOrWhiteSpace(houseNo), m => m.WareHouseNo == houseNo)
                    .AndIF(!string.IsNullOrWhiteSpace(roadwayNo), m => m.RoadwayNo == roadwayNo)
                    .AndIF(!string.IsNullOrWhiteSpace(locateNo), m => m.LocatNo == locateNo)
                    .AndIF(!string.IsNullOrWhiteSpace(palletNo), m => m.PalletNo == palletNo)
                    .AndIF(!string.IsNullOrWhiteSpace(msg),
                        m => m.SkuNo.Contains(msg.Trim())
                             || m.SkuName.Contains(msg.Trim())
                             || m.LocatNo.Contains(msg.Trim()))
                    .And(m => m.IsDel == "0" && m.SkuNo == detail.SkuNo && m.LotNo == detail.LotNo && (m.Status == "0" || m.Status == "1"))
                    .ToExpression();//注意 这一句 不能少
                var list = Db.Queryable<DataStockDetail>().Where(item).Select(a => new StockDetailDto
                {
                    Id = a.Id,
                    SkuNo = a.SkuNo,
                    SkuName = a.SkuName,
                    Standard = a.Standard,
                    LotNo = a.LotNo,
                    LotText = a.LotText,
                    SupplierLot = a.SupplierLot,
                    Qty = a.Qty - a.LockQty - a.FrozenQty,
                    LocatNo = a.LocatNo,
                    RoadwayNo = a.RoadwayNo,
                    PalletNo = a.PalletNo,
                    Demo = a.Demo,
                }).ToList();
                return list;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        //手动分配出库单明细
        public void AddHandOutAllot(AddHandOutVm model, int userId)
        {
            try
            {
                #region 判断条件
                //数据验证
                var detail = Db.Queryable<BllExportNoticeDetail>().First(a => a.IsDel == "0" && a.Id == model.Id);
                if (detail == null)
                {
                    throw new Exception("操作失败,未找到指定出库单详情!");
                }
                if (detail.AllotQty >= detail.Qty || (detail.Status != "0" && detail.Status != "1"))
                {
                    throw new Exception("操作失败,出库单已分配完成!");
                }
                var notice = Db.Queryable<BllExportNotice>().First(a => a.IsDel == "0" && a.SONo == detail.SONo);
                if (notice == null)
                {
                    throw new Exception("操作失败,未找到指定出库单!");
                }
                if (notice.Status == "3" && detail.AllotQty >= detail.Qty || notice.Status == "4" || notice.Status == "5")
                {
                    throw new Exception("操作失败,出库单已分配完成!");
                }
                #endregion
                //单据明细需要的出库数量
                var needQty = detail.Qty - detail.AllotQty;
                //分配的出库数量
                var outQty = model.StockList.Select(s => s.Qty).ToList().Sum();
                if (outQty != needQty)
                {
                    throw new Exception("操作失败,出库数量与计划数量不一致!");
                }
                var stockIds = model.StockList.Select(a => a.StockId).ToList();
                //库存明细
                var stockList = Db.Queryable<DataStockDetail>().Where(a => stockIds.Contains(a.Id)).ToList();
                //分配信息
                var allots = Db.Queryable<BllExportAllot>().Where(m => m.IsDel == "0" && m.SODetailNo == detail.Id && m.Status == "0").ToList();
                //库存总表
                //var stockz = Db.Queryable<DataStock>().First(d => d.IsDel == "0" && d.SkuNo == detail.SkuNo && d.LotNo == detail.LotNo);
                var allotList = new List<BllExportAllot>();
                decimal outQtys = 0;
                foreach (var st in model.StockList)
                {
                    var stock = stockList.First(a => a.Id == st.StockId);
                    if (stock == null)
                    {
                        throw new Exception("操作失败,部分储位库存异常!");
                    }
                    if (st.Qty > (stock.Qty - stock.LockQty - stock.FrozenQty))     // 输入的数量 -  托盘上可用的数量(托盘上数量-锁定的数量-冻结的数量)
                    {
                        throw new Exception("操作失败,出库数量超出库存数量!");
                    }
                    var bl = allots.FirstOrDefault(m => m.StockId == st.StockId);
                    if (bl == null)
                    {
                        //添加分配表信息
                        var allot = new BllExportAllot
                        {
                            SONo = notice.SONo,
                            WaveNo = "",
                            SODetailNo = detail.Id,
                            StockId = st.StockId,
                            LotNo = stock.LotNo,
                            LotText = stock.LotText,
                            SupplierLot = stock.SupplierLot,
                            SkuNo = stock.SkuNo,
                            SkuName = stock.SkuName,
                            Standard = stock.Standard,
                            PalletNo = stock.PalletNo,
                            IsBale = stock.IsBale,
                            IsBelt = stock.IsBelt,
                            Qty = st.Qty,
                            CompleteQty = 0,
                            Status = "0",
                            LogisticsId = notice.LogisticsId,
                            IsAdvance = "0",
                            OutMode = "",//出库口
                            CreateUser = userId,
                            CreateTime = DateTime.Now
                        };
                        allotList.Add(allot);
                    }
                    else
                    {
                        bl.Qty += st.Qty;
                        Db.Updateable(bl).ExecuteCommand();
                    }
                    //库存明细
                    stock.LockQty += st.Qty;
                    stock.Status = stock.LockQty == stock.Qty ? "2" : "1";
                    //库存总表
                    //stockz.LockQty += st.Qty;
                    //Db.Updateable(stockz).ExecuteCommand();
                    Db.Updateable(stock).UpdateColumns(it => new { it.LockQty, it.Status }).ExecuteCommand();
                    outQtys += st.Qty;
                }
                Db.Insertable(allotList).ExecuteCommand();
                //修改单据明细
                detail.AllotQty += outQtys;
                detail.UpdateUser = userId;
                detail.UpdateTime = DateTime.Now;
                if (detail.Status == "0")
                {
                    detail.Status = "1";
                }
                Db.Updateable(detail).ExecuteCommand();
                var detailList = Db.Queryable<BllExportNoticeDetail>()
                    .Where(m => m.IsDel == "0" && m.SONo == notice.SONo).ToList();
                //修改出库单状态
                if (notice.Status == "0" || notice.Status == "1")
                {
                    decimal totalQty = 0;
                    decimal totalAllotQty = 0;
                    foreach (var item in detailList)
                    {
                        totalQty += item.Qty;
                        totalAllotQty += Convert.ToInt32(item.AllotQty);
                    }
                    if (totalAllotQty >= totalQty)
                    {
                        notice.Status = "2";//证明分配数量大于等于出库数量  修改为已分配
                    }
                    else if (totalAllotQty < totalQty && totalAllotQty > 0)
                    {
                        notice.Status = "1";//证明分配数量小于等于出库数量  修改为部分分配
                    }
                    Db.Updateable(notice).ExecuteCommand();
                }
                //添加操作日志记录
                var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "分配", $"手动分配了单据号为{notice.SONo}、物料:{detail.SkuNo}、批次:{detail.LotNo}的单据信息", userId);
                Db.CommitTran();
            }
            catch (Exception e)
            {
                Db.RollbackTran();
                throw new Exception(e.Message);
            }
        }
        #endregion
        #region 下发出库、出库完成、重新下发任务、取消任务、异常处理
        public string GetHouseBySo(string soNo)
        {
            try
            {
                var notcie = Db.Queryable<BllExportNotice>().First(m=>m.IsDel == "0" && m.SONo == soNo);
                if (notcie == null)
                {
                    throw new Exception("未查询到出库单信息");
                }
                return notcie.WareHouseNo;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        public List<OutCommandDto> IssueOutHouseLk(string soNo, string outMode, int userId, string url, out string str)
        {
            try
            {
                var outDto1 = new List<OutCommandDto>(); //出库数据的集合(深度为1的储位)
                //记录错误信息的集合 //1:当前要出库的储位正在移出、2 出库的托盘储位信息错误(在储位表中未查询到)、3储位损坏不能出库、4 要出库的托盘正在入库
                var flagList = new List<int>();
                var com = new Common();
                var notice = Db.Queryable<BllExportNotice>().First(m => m.SONo == soNo && m.IsDel == "0");
                if (notice == null)
                {
                    throw new Exception($"未找到{soNo}出库单信息");
                }
                if (notice.WareHouseNo != "W02")
                {
                    throw new Exception("仓库号错误");
                }
                //所有要出库的出库分配信息(未下发的信息和待拣货的信息)
                var list = Db.Queryable<BllExportAllot>().Where(a => a.IsDel == "0" && a.SONo == soNo && (a.Status == "0" || a.Status == "2")).ToList();
                if (list.Count == 0) //判断是否有需要下发的出库流水
                {
                    throw new Exception("当前出库单据无需要下发的托盘");
                }
                #region 集合
                //要出库的托盘集合
                var outLpnList = list.Select(m => m.PalletNo).ToList();
                //要出库的明细集合
                var outStockDetail = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && outLpnList.Contains(m.PalletNo)).ToList();
                //物料编码表
                var skuList = Db.Queryable<SysMaterials>().Where(w => w.IsDel == "0");
                //包装表
                var packagList = Db.Queryable<SysPackag>().Where(w => w.IsDel == "0");
                Db.BeginTran();
                try
                {
                    List<LogTask> logTaskList = new List<LogTask>();//此次出库任务集合,为应对同托盘不同物料出库
                    //循环分配的信息生成出库任务
                    foreach (var item in list)
                    {
                        var taskNoStr = "";
                        // 储位号
                        var locateNo = outStockDetail.First(m => m.PalletNo == item.PalletNo).LocatNo;
                        #region 判断
                        //判断托盘是否在库内
                        if (string.IsNullOrWhiteSpace(locateNo)) //库外
                        {
                            //判断托盘是否在入库中
                            var imBl = com.GetImTask(item.PalletNo);
                            if (imBl != null)
                            {
                                flagList.Add(4);
                                continue;
                            }
                            //判断是否是已经出过库又回库(状态为待拣货的)
                            if (item.Status == "0")
                            {
                                //如果不在仓库内,当前分配信息直接更新出库完成
                                item.Status = "2";//状态
                                item.OutMode = outMode;//出库口
                                Db.Updateable(item).ExecuteCommand();
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            flagList.Add(0);
                            continue;
                        }
                        var locate = Db.Queryable<SysStorageLocat>().First(m => m.LocatNo == locateNo && m.IsDel == "0");//当前出库的储位信息
                        if (locate == null)
                        {
                            flagList.Add(2);
                            continue;
                        }
                        //判断储位标志是否为损坏
                        if (locate.Flag == "2")
                        {
                            flagList.Add(3);
                            continue;
                        }
                        #endregion
                        if (locate.Status == "1") //有物品
                        {
                            #region 添加出库任务
                            var taskNo = new Common().GetMaxNo("TK");
                            var exTask = new LogTask    //出库任务
                            {
                                TaskNo = taskNo,
                                Sender = "WMS",
                                Receiver = "WCS",
                                IsSuccess = 0, //是否下发成功 0失败 1成功
                                StartLocat = locate.LocatNo,//起始位置
                                EndLocat = outMode,//目标位置
                                PalletNo = item.PalletNo,//托盘码
                                IsSend = 1,//是否可再次下发
                                IsCancel = 1,//是否可取消
                                IsFinish = 1,//是否可完成
                                Type = "1",//任务类型 0 入库任务 1 出库任务  2 移库任务
                                Status = "0",//任务状态0:等待执行1正在执行2执行完成
                                OrderType = "1",//0 入库单 1 出库单  2 盘点单  3 移库单
                                Msg = "从" + locate.LocatNo + "到" + outMode + "的出库任务", //关键信息
                            };
                            Db.Insertable(exTask).ExecuteCommand();
                            logTaskList.Add(exTask);
                            outDto1.Add(new OutCommandDto()
                            {
                                PalletNo = item.PalletNo,//托盘号
                                StartLocate = locate.LocatNo, // 起始位置
                                StartRoadway = locate.RoadwayNo,//其实巷道
                                EndLocate = outMode, // 目标位置
                                TaskNo = exTask.TaskNo, // 任务号
                                TaskType = "1",// 任务类型 (出库)0入 1出 2移
                                OutMode = outMode,  //出库口
                                Order = 1,
                                //UnstackingMode = "unstackingMode2",//拣货方式 0机器拆托出  1 人工拣货出
                                //CompleteQty = outCount2,  //拆的件数
                                //BoxexQty = outCount,      //总件数
                            });
                            taskNoStr = exTask.TaskNo;
                            #endregion
                            #region 改变数据
                            if (item.Status == "0")//判断托盘是否下发过
                            {
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            locate.Status = "3"; //要出库的储位改变状态 正在出库
                            Db.Updateable(locate).ExecuteCommand();
                            item.TaskNo = taskNoStr; // 出库分配信息中更新任务号
                            item.Status = "1"; // 出库分配信息状态改为正在执行
                            //item.UnstackingMode = unstackingMode2;//拆垛方式
                            item.OutMode = outMode;//出库口
                            //item.LoadingAddre = unstackingMode2 == "0" ? loadingAddre : "";//装车口
                            Db.Updateable(item).ExecuteCommand();
                            #endregion
                            flagList.Add(0);
                        }
                        else if (locate.Status == "3") //出库中
                        {
                            #region 改变数据
                            //判断是否是已经出过库又回库(状态为待拣货的 1)
                            if (item.Status == "0")
                            {
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            var taskNo = Db.Queryable<LogTask>().First(m => m.OrderType == "1" && m.TaskNo != item.TaskNo && m.Status == "1" && m.PalletNo == item.PalletNo);
                            if (taskNo == null)
                            {
                                taskNo = logTaskList.FirstOrDefault(m => m.PalletNo == item.PalletNo);//当前有同托盘不同物料出库
                            }
                            if (taskNo == null)
                            {
                                throw new Exception($"托盘号:{item.PalletNo},出库异常");
                            }
                            item.TaskNo = taskNo.TaskNo;
                            item.Status = "1"; // 出库分配信息状态改为正在执行
                            item.OutMode = item.OutMode;//出库口
                            //item.UnstackingMode = unstackingMode2;//拆垛模式
                            Db.Updateable(item).ExecuteCommand();
                            flagList.Add(0);
                            #endregion
                        }
                        else if (locate.Status == "5") //移出中
                        {
                            flagList.Add(1);
                        }
                    }
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", soNo, "出库", $"点击出库按钮出库单号为:{soNo}的出库单", userId);
                    Db.CommitTran();
                    str = string.Empty;
                    if (flagList.Count(m => m == 0) > 0)
                    {
                        str += "0.下发成功、";
                    }
                    if (flagList.Count(m => m == 1) > 0)
                    {
                        str += "1.当前要出库的储位正在移出、";
                    }
                    if (flagList.Count(m => m == 2) > 0)
                    {
                        str += "2.出库的托盘储位信息错误(在储位表中未查询到)、";
                    }
                    if (flagList.Count(m => m == 3) > 0)
                    {
                        str += "4.储位损坏不能出库、";
                    }
                    if (flagList.Count(m => m == 4) > 0)
                    {
                        str += "3.要出库的托盘正在入库、";
                    }
                    if (flagList.Count(m => m == 5) > 0)
                    {
                        str += "3.要出库的托盘正在拆托请稍后下发、";
                    }
                    if (outDto1.Count > 0)
                    {
                        // 正式运行程序放开
                        var list2 = outDto1.Select(m => m.TaskNo).ToList();
                        var jsonData = JsonConvert.SerializeObject(outDto1);
                        string response = "";
                        try
                        {
                            var time1 = DateTime.Now;//发送时间 .ToString("yyyy-MM-dd HH:mm:ss")
                            //response = HttpHelper.DoPost(url, jsonData, "下发给WCS出库命令", "WCS");
                            var time2 = DateTime.Now;//返回时间 .ToString("yyyy-MM-dd HH:mm:ss")
                            //////解析返回数据
                            //var wcsModel = JsonConvert.DeserializeObject<WcsModel>(response);
                            //if (wcsModel.StatusCode == 0)
                            //{
                            //    //更改任务的发送返回时间//
                                new TaskServer().EditTaskIssueOk(list2, time1, time2);
                                str += "下发成功";
                            //}
                            //if (wcsModel.StatusCode == -1)
                            //{
                            //    new TaskServer().EditTaskIssueNo(list2, time1, time2, wcsModel.Msg);
                            //    throw new Exception(wcsModel.Msg);
                            //}
                        }
                        catch (Exception ex)
                        {
                            throw new Exception(ex.Message);
                        }
                    }
                    return outDto1;
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
                #endregion
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        public List<OutCommandDto> IssueOutHouseMk(string soNo, string outMode, int userId, string url, out string str)
        {
            try
            {
                #region 集合
                var outDto1 = new List<OutCommandDto>(); //先出库数据的集合(深度为1的储位)
                var outDto2 = new List<OutCommandDto>(); //后出库数据的集合(深度为2的储位)
                var moveDto = new List<OutCommandDto>(); //要移库数据的集合
                //记录错误信息的集合
                var flagList = new List<int>();//1:当前要出库的储位正在移出、2 出库的托盘储位信息错误(在储位表中未查询到)、3储位损坏不能出库、4 要出库的托盘正在入库
                #endregion
                var com = new Common();
                var notice = Db.Queryable<BllExportNotice>().First(m => m.SONo == soNo && m.IsDel == "0");
                if (notice == null)
                {
                    throw new Exception($"未找到{soNo}出库单信息");
                }
                //所有要出库的出库分配信息(未下发的信息和待拣货的信息)
                var list = Db.Queryable<BllExportAllot>().Where(a => a.IsDel == "0" && a.SONo == soNo && (a.Status == "0" || a.Status == "2")).ToList();
                if (list.Count == 0) //判断是否有需要下发的出库流水
                {
                    throw new Exception("当前出库单据无需要下发的托盘");
                }
                #region 集合
                //要出库的托盘集合
                var outLpnList = list.Select(m => m.PalletNo).ToList();
                //要出库的明细集合
                var outStockDetail = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && outLpnList.Contains(m.PalletNo)).ToList();
                //所有要出库的储位集合
                var locateListStrs = outStockDetail.Where(m=> !string.IsNullOrWhiteSpace(m.LocatNo)).Select(m => m.LocatNo).Distinct().ToList();
                //物料编码表
                var skuList = Db.Queryable<SysMaterials>().Where(w => w.IsDel == "0");
                //包装表
                var packagList = Db.Queryable<SysPackag>().Where(w => w.IsDel == "0");
                Db.BeginTran();
                try
                {
                    List<LogTask> logTaskList = new List<LogTask>();//此次出库任务集合,为应对同托盘不同物料出库
                    //循环分配的信息生成出库任务
                    foreach (var item in list)
                    {
                        var taskNoStr = "";
                        string toLocation = string.Empty;//目标位置
                        // 储位号
                        var locateNo = outStockDetail.First(m => m.PalletNo == item.PalletNo).LocatNo;
                        #region 判断托盘是否在库内
                        //判断托盘是否在库内
                        if (string.IsNullOrWhiteSpace(locateNo)) //库外
                        {
                            if (notice.Type == "0")
                            {
                                flagList.Add(5);
                                continue;
                            }
                            //判断托盘是否在入库中
                            var imBl = com.GetImTask(item.PalletNo);
                            if (imBl != null)
                            {
                                flagList.Add(4);
                                continue;
                            }
                            //判断是否是已经出过库又回库(状态为待拣货的 1)
                            if (item.Status == "0")
                            {
                                //如果不在仓库内,当前分配信息直接更新出库完成
                                item.Status = "2";//状态
                                item.OutMode = outMode;//出库口
                                Db.Updateable(item).ExecuteCommand();
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            flagList.Add(0);
                            continue;
                        }
                        //判断储位
                        var locate = Db.Queryable<SysStorageLocat>().First(m => m.LocatNo == locateNo && m.IsDel == "0");//当前出库的储位信息
                        if (locate == null)
                        {
                            flagList.Add(2);
                            continue;
                        }
                        //判断储位标志是否为损坏
                        if (locate.Flag == "2")
                        {
                            flagList.Add(3);
                            continue;
                        }
                        #endregion
                        if (locate.Status == "1") //有物品
                        {
                            var row1 = int.Parse(locate.LocatNo.Substring(2,2));
                            var row2 = int.Parse(locate.AisleOne.Substring(2, 2));
                            //需要移库的信息
                            var NeedMoveInfo = IsNeedMoveLocate(locate, locateListStrs, out int isOut);
                            if (isOut == 1)
                            {
                                //巷道组中有入库或移入的储位,或者是当前储位前有储位未下发成功的任务
                                flagList.Add(2);
                                continue;
                            }
                            if (NeedMoveInfo.Count > 0)//需要移库
                            {
                                //判断库内空储位是否够
                                var okRoad = Db.Queryable<SysStorageRoadway>().Where(m => m.Status == "0" && m.IsDel == "0" && m.WareHouseNo == notice.WareHouseNo).Select(m => m.RoadwayNo).ToList();
                                var nullSlotNum = Db.Queryable<SysStorageLocat>().Count(m => m.RoadwayNo != locate.RoadwayNo && okRoad.Contains(m.RoadwayNo) && m.Status == "0");
                                //判断空储位的数量是否大于需要移库的数量
                                if (nullSlotNum >= NeedMoveInfo.Count)
                                {
                                    var isYk = false;
                                    foreach (var s in NeedMoveInfo)
                                    {
                                        //储位列
                                        var rows = int.Parse(s.Substring(2,2));
                                        //获取移库储位
                                        var moveAddress = GetMiJiMoveAddress(s, locate.AisleOne);
                                        var tary = Db.Queryable<DataStockDetail>().First(m => m.LocatNo == s);
                                        if (string.IsNullOrWhiteSpace(moveAddress)) // 判断是否获取到移库的库位
                                        {
                                            isYk = true;
                                            flagList.Add(5);//出库前有货物,需移库但未查询到空储位
                                            break; //没有移库的库位了
                                        }
                                        else
                                        {
                                            //判断托盘有没有回移的任务
                                            //var hy = GetHyTask(item.ExportStockCode);
                                            //if (hy != null)
                                            //{
                                            //    var hyentity = dataContext.WmsExportTask.FirstOrDefault(m => m.TaskId == hy.TaskId);
                                            //    if (hyentity != null)
                                            //    {
                                            //        isYk = true;
                                            //        msgList.Add(6);//出库前有货物,需移库但是回移托盘
                                            //        break; //没有移库的库位了
                                            //    }
                                            //}
                                            var ykTaskNo = new Common().GetMaxNo("TK");
                                            var ykTask = new LogTask    //出库任务
                                            {
                                                TaskNo = ykTaskNo,
                                                Sender = "WMS",
                                                Receiver = "WCS",
                                                IsSuccess = 0, //是否下发成功 0失败 1成功
                                                StartLocat = s,//起始位置
                                                EndLocat = moveAddress,//outMode,//目标位置
                                                PalletNo = tary.PalletNo,//托盘码
                                                IsSend = 1,//是否可再次下发
                                                IsCancel = 1,//是否可取消
                                                IsFinish = 1,//是否可完成
                                                Type = "2",//任务类型 0 入库任务 1 出库任务  2 移库任务
                                                Status = "0",//任务状态0:等待执行1正在执行2执行完成
                                                OrderType = "1",//0 入库单 1 出库单  2 盘点单  3 移库单
                                                Msg = "从" + locate.LocatNo + "到" + toLocation + "的出库任务", //关键信息
                                            };
                                            Db.Insertable(ykTask).ExecuteCommand();
                                            logTaskList.Add(ykTask);
                                            outDto1.Add(new OutCommandDto()
                                            {
                                                PalletNo = item.PalletNo,//托盘号
                                                StartLocate = locate.LocatNo, // 起始位置
                                                StartRoadway = locate.RoadwayNo,//其实巷道
                                                EndLocate = toLocation,//outMode, // 目标位置
                                                TaskNo = ykTaskNo, // 任务号
                                                TaskType = "1",// 任务类型 (出库)0入 1出 2移
                                                Order = Math.Abs(row2 - rows),
                                            });
                                            var slotChange = Db.Queryable<SysStorageLocat>().First(m => m.LocatNo == s);
                                            var slotChange2 = Db.Queryable<SysStorageLocat>().First(m => m.LocatNo == moveAddress);
                                            slotChange.Status = "5"; //改变状态(正在出库)
                                            slotChange2.Status = "4"; // 改变状态(正在移入)
                                            Db.Updateable(slotChange).ExecuteCommand();
                                            Db.Updateable(slotChange2).ExecuteCommand();
                                        }
                                    }
                                    if (isYk)
                                    {
                                        break;
                                    }
                                }
                                else
                                {
                                    flagList.Add(5);
                                    break;
                                }
                            }
                            #region 添加出库任务
                            var taskNo = new Common().GetMaxNo("TK");
                            var exTask = new LogTask    //出库任务
                            {
                                TaskNo = taskNo,
                                Sender = "WMS",
                                Receiver = "WCS",
                                IsSuccess = 0, //是否下发成功 0失败 1成功
                                StartLocat = locate.LocatNo,//起始位置
                                EndLocat = toLocation,//outMode,//目标位置
                                PalletNo = item.PalletNo,//托盘码
                                IsSend = 1,//是否可再次下发
                                IsCancel = 1,//是否可取消
                                IsFinish = 1,//是否可完成
                                Type = "1",//任务类型 0 入库任务 1 出库任务  2 移库任务
                                Status = "0",//任务状态0:等待执行1正在执行2执行完成
                                OrderType = "1",//0 入库单 1 出库单  2 盘点单  3 移库单
                                Msg = "从" + locate.LocatNo + "到" + toLocation + "的出库任务", //关键信息
                            };
                            Db.Insertable(exTask).ExecuteCommand();
                            logTaskList.Add(exTask);
                            outDto1.Add(new OutCommandDto()
                            {
                                PalletNo = item.PalletNo,//托盘号
                                StartLocate = locate.LocatNo, // 起始位置
                                StartRoadway = locate.RoadwayNo,//其实巷道
                                EndLocate = toLocation,//outMode, // 目标位置
                                TaskNo = exTask.TaskNo, // 任务号
                                TaskType = "1",// 任务类型 (出库)0入 1出 2移
                                OutMode = toLocation,  //出库口
                                Order = Math.Abs(row2 - row1),
                            });
                            taskNoStr = exTask.TaskNo;
                            #endregion
                            #region 改变数据
                            if (item.Status == "0")//判断托盘是否下发过
                            {
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            locate.Status = "3"; //要出库的储位改变状态 正在出库
                            Db.Updateable(locate).ExecuteCommand();
                            item.TaskNo = taskNoStr; // 出库分配信息中更新任务号
                            item.Status = "1"; // 出库分配信息状态改为正在执行
                            //item.UnstackingMode = unstackingMode2;//拆垛方式
                            item.OutMode = outMode;//出库口
                            //item.LoadingAddre = unstackingMode2 == "0" ? loadingAddre : "";//装车口
                            Db.Updateable(item).ExecuteCommand();
                            #endregion
                            flagList.Add(0);
                        }
                        else if (locate.Status == "3") //出库中
                        {
                            #region 改变数据
                            //判断是否是已经出过库又回库(状态为待拣货的 1)
                            if (item.Status == "0")
                            {
                                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().First(m => m.IsDel == "0" && m.Id == item.SODetailNo);
                                if (noticeDetail != null) //更新出库单据的下发数量
                                {
                                    noticeDetail.FactQty += item.Qty;
                                    Db.Updateable(noticeDetail).ExecuteCommand();
                                }
                                //var notice2 = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.SONo == item.SONo);
                                if (notice.Status == "0" || notice.Status == "1" || notice.Status == "2")
                                {
                                    var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == item.SONo).ToList();
                                    if (detailList.Count(m => m.Qty >= m.AllotQty) > 0)
                                    {
                                        notice.Status = "3"; //变更状态为正在执行
                                        Db.Updateable(notice).ExecuteCommand();
                                    }
                                }
                            }
                            var taskNo = Db.Queryable<LogTask>().First(m => m.OrderType == "1" && m.TaskNo != item.TaskNo && m.Status == "1" && m.PalletNo == item.PalletNo);
                            if (taskNo == null)
                            {
                                taskNo = logTaskList.FirstOrDefault(m => m.PalletNo == item.PalletNo);//当前有同托盘不同物料出库
                            }
                            if (taskNo == null)
                            {
                                throw new Exception($"托盘号:{item.PalletNo},出库异常");
                            }
                            item.TaskNo = taskNo.TaskNo;
                            item.Status = "1"; // 出库分配信息状态改为正在执行
                            item.OutMode = item.OutMode;//出库口
                            //item.UnstackingMode = unstackingMode2;//拆垛模式
                            Db.Updateable(item).ExecuteCommand();
                            flagList.Add(0);
                            #endregion
                        }
                        else if (locate.Status == "5") //移出中
                        {
                            flagList.Add(1);
                        }
                    }
                    outDto1.AddRange(moveDto);
                    outDto1.AddRange(outDto2);
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", soNo, "出库", $"点击出库按钮出库单号为:{soNo}的出库单", userId);
                    Db.CommitTran();
                    str = string.Empty;
                    if (flagList.Count(m => m == 0) > 0)
                    {
                        str += "0.下发成功、";
                    }
                    if (flagList.Count(m => m == 1) > 0)
                    {
                        str += "1.当前要出库的储位正在移出、";
                    }
                    if (flagList.Count(m => m == 2) > 0)
                    {
                        str += "2.出库的托盘储位信息错误(在储位表中未查询到)、";
                    }
                    if (flagList.Count(m => m == 3) > 0)
                    {
                        str += "4.储位损坏不能出库、";
                    }
                    if (flagList.Count(m => m == 4) > 0)
                    {
                        str += "3.要出库的托盘正在入库、";
                    }
                    if (flagList.Count(m => m == 5) > 0)
                    {
                        str += "3.要出库的托盘正在拆托请稍后下发、";
                    }
                    if (outDto1.Count > 0)
                    {
                        // 正式运行程序放开
                        var list2 = outDto1.Select(m => m.TaskNo).ToList();
                        var jsonData = JsonConvert.SerializeObject(outDto1);
                        string response = "";
                        try
                        {
                            //var time1 = DateTime.Now;//发送时间 .ToString("yyyy-MM-dd HH:mm:ss")
                            //response = HttpHelper.DoPost(url, jsonData, "下发给WCS出库命令", "WCS");
                            //var time2 = DateTime.Now;//返回时间 .ToString("yyyy-MM-dd HH:mm:ss")
                            //////解析返回数据
                            //var wcsModel = JsonConvert.DeserializeObject<WcsModel>(response);
                            //if (wcsModel.StatusCode == 0)
                            //{
                            //    //更改任务的发送返回时间//
                            //    new TaskServer().EditTaskIssueOk(list2, time1, time2);
                            //    str += "下发成功";
                            //}
                            //if (wcsModel.StatusCode == -1)
                            //{
                            //    new TaskServer().EditTaskIssueNo(list2, time1, time2, wcsModel.Msg);
                            //    throw new Exception(wcsModel.Msg);
                            //}
                        }
                        catch (Exception ex)
                        {
                            throw new Exception(ex.Message);
                        }
                    }
                    return outDto1;
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
                #endregion
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        /// <summary>
        /// 判断是否需要进行移库操作
        /// </summary>
        /// <param name="oldAddress">要出库的库位地址</param>
        /// <param name="aisle">通道口</param>
        /// <param name="addressList">要出口的储位集合</param>
        /// <param name="isOut">是否出库 1:有未下发的任务在前面</param>
        /// <returns>需要移库的集合(如果为空则不需移库)</returns>
        private List<string> IsNeedMoveLocate(SysStorageLocat lcoate,List<string> locateStrList, out int isOut)
        {
            var nowAddress = new List<string>(); //需要移库的集合
            // 010101 派列层
            //var bol = String.CompareOrdinal(lcoate.LocatNo, lcoate.AisleOne);
            var sArray = lcoate.LocatNo.Substring(4,2);
            var row = int.Parse(sArray);//储位列
            var sArray2 = lcoate.AisleOne.Substring(4, 2);
            var row2 = int.Parse(sArray2); //通道口列
            isOut = 0;
            var bol = row2 - row > 0;
            //同组的储位集合
            var slotList = Db.Queryable<SysStorageLocat>().Where(m => m.RoadwayNo == lcoate.RoadwayNo).ToList();
            List<string> list;
            if (bol)
            {
                //储位小于通道口   倒序
                list = slotList.Where(m => m.Column < row2 && m.Column > row).Select(m => m.LocatNo).ToList();
            }
            else
            {
                //储位大于通道口   正序
                list = slotList.Where(m => m.Column > row2 && m.Column < row).Select(m => m.LocatNo).ToList();
            }
            if (list.Any())
            {
                //排除掉同巷道组中要出库的储位
                if (locateStrList.Count != 0)
                {
                    list = list.Where(m => !locateStrList.Contains(m)).ToList();
                }
                //判断是否有入库中或正在移入的
                var s = slotList.Where(m => list.Contains(m.LocatNo) && (m.Status == "2" || m.Status == "4")).Select(m => m.LocatNo).ToList();
                if (s.Count > 0)
                {
                    isOut = 1;
                    return nowAddress;
                }
                //判断是否有在当前储位前未下发的任务(防止撞车)
                var w = Db.Queryable<LogTask>().Where(m => list.Contains(m.StartLocat) && m.IsSuccess == 0).Select(m => m.StartLocat).ToList();
                if (w.Count > 0)
                {
                    isOut = 1;
                    return nowAddress;
                }
                if (bol)
                {
                    //储位小于通道口   倒序
                    nowAddress = slotList.Where(m => list.Contains(m.LocatNo) && m.Status == "1").OrderByDescending(m => m.LocatNo).Select(m => m.LocatNo).ToList();
                }
                else
                {
                    //储位大于通道口   正序
                    nowAddress = slotList.Where(m => list.Contains(m.LocatNo) && m.Status == "1").OrderBy(m => m.LocatNo).Select(m => m.LocatNo).ToList();
                }
                if (nowAddress.Count > 0)
                {
                    return nowAddress;
                }
            }
            else
            {
                return nowAddress;
            }
            return nowAddress;
        }
        /// <summary>
        /// 获取移库目标库位 密集库
        /// </summary>
        /// <param name="oldAddress">需要移动的库位地址</param>
        /// <param name="slotOut">需要移动的库位的出口中转位</param>
        /// <param name="billCode">出库单据或是波次单据</param>
        /// <param name="flags">中转口</param>
        /// <param name="refLanWayId">需回移的巷道id</param>
        /// <param name="refLanOutCode">需回移的巷道中转口</param>
        /// <returns>目标库位地址 为"" 直接下发两次出库指令</returns>
        public string GetMiJiMoveAddress(string oldAddress, string slotOut)
        {
            var newAddress = ""; //新库位
            var newLaneWayAddress = ""; //新巷道口库位
            // 获取移库目标储位
            //
            var sArray = oldAddress.Substring(4,2);
            var ceng = int.Parse(sArray);
            //
            var sArray2 = slotOut.Substring(2, 2);
            var row2 = sArray2;
            //十字口
            var shiKou = new List<string>()
            {
                slotOut,
                "070501",
                "071301",
                "070502",
                "071302",
            };
            var shiKou3 = new List<addreClass>();
            foreach (var item in shiKou)
            {
                var a = item.Substring(4, 2);
                var b = item.Substring(2, 2);
                if (int.Parse(a) != ceng) continue;
                var s = Math.Abs(int.Parse(b) - int.Parse(row2));
                if (shiKou3.Any(m => m.distNum == s)) continue;
                shiKou3.Add(new addreClass()
                {
                    slotCode = item,
                    distNum = s
                });
            }
            //根据十字口差值最小的排序
            shiKou3 = shiKou3.OrderBy(m => m.distNum).ToList();
                /**
                //1 移动到最近的空储位,必须回移。
                //根据四向车移动轨迹计算出最近空储位。
                //出库完成后根据批次号 生产日期 出口计算回移储位。
                //2 移动适合存放的组,系统自动计算是否回移。
                //根据批次号 生产日期 出口 物料等计算出移库目标储位
                //出库完成后,判断是否有比当前库位更合适的存储储位,有移动,无不移动。
                */
                var oldSlot = Db.Queryable<SysStorageLocat>().First(m => m.LocatNo == oldAddress);
                if (oldSlot == null)
                {
                    throw new Exception("未能找到储位信息");
                }
                #region 1不需要回移的
                //后期库存托盘表改了后需要加筛选条件托盘的状态(退货/预拣)
                var tray1 = Db.Queryable<DataStockDetail>().Where(m => m.LocatNo == oldAddress).ToList();
                //根据物料、批次、托盘状态(退货/预拣/暂存等)分组判断
                var d = tray1.GroupBy(m => new { m.SkuNo, m.LotNo, m.PalletTags });
                var location = string.Empty;
                if (d.Any())
                {
                    //旧储位同组的储位集合
                    var slotList = Db.Queryable<SysStorageLocat>().Where(m => m.RoadwayNo == oldSlot.RoadwayNo).Select(m => m.LocatNo).ToList();
                    foreach (var item in d)
                    {
                        foreach (var item2 in item)
                        {
                            var okLan = Db.Queryable<SysStorageRoadway>().Where(m => m.Status == "0" && m.IsDel == "0").Select(m => m.RoadwayNo).ToList();
                            var tray2 = Db.Queryable<DataStockDetail>().Where(m => m.SkuNo == item2.SkuNo
                            && m.LotNo == item2.LotNo && !slotList.Contains(m.LocatNo) && m.PalletTags == item2.PalletTags && okLan.Contains(m.RoadwayNo)).ToList();
                            foreach (var s in tray2)
                            {
                                if (string.IsNullOrWhiteSpace(s.RoadwayNo))//判断是否在库外,如是跳过
                                {
                                    continue;
                                }
                                var lan = Db.Queryable<SysStorageLocat>().Where(m => m.RoadwayNo == s.RoadwayNo).OrderBy(m => m.LocatNo).ToList();
                                //判断是否有入库中、出库中、移入中、移出中
                                if (lan.Count(m => m.Status == "2" || m.Status == "3" || m.Status == "4" || m.Status == "5") > 0)
                                {
                                    continue;
                                }
                                if (lan.Count(m => m.Status == "0") > 0)
                                {
                                    var bol = GetBecomingLocation(s.RoadwayNo, ref location);
                                    if (bol && !string.IsNullOrWhiteSpace(location))
                                    {
                                        newAddress = location;
                                        return newAddress;
                                    }
                                }
                            }
                        }
                    }
                }
                #endregion
                #region 2需要回移的
                ////如果没有找到合适的储位
                //if (string.IsNullOrWhiteSpace(newAddress))
                //{
                //    foreach (var s in shiKou3)
                //    {
                //        var r = int.Parse(s.slotCode.Substring(0, 2));
                //        var l = int.Parse(s.slotCode.Substring(2, 2));
                //        var c = int.Parse(s.slotCode.Substring(4, 2));
                //        //查询空储位
                //        var sqlString = $@"select LocatNo,Row,Column,Layer,(ABS(Row-{r}) + ABS(Column-{l}) ) as distNum
                //                from SysStorageLocat where (AisleOneRow  = {r} or AisleTwoRow = {r}) and Status in (0) and
                //                 RoadwayNo !='{oldSlot.RoadwayNo}' and RoadwayNo not in(select RoadwayNo from SysStorageRoadway where Status = 1) order by distNum,SlotCode";
                //        var addressModels = dataContext.ExecuteQuery<addreClass>(sqlString).ToList();
                //        foreach (var item in addressModels)
                //        {                            、
                //            newAddress = item.slotCode;
                //            var dz = newAddress.Split(new char[] { '-' });
                //            var l1 = dz[1];
                //            var c1 = dz[0];
                //            newLaneWayAddress = $"{c1}-{l1}-{a[2]}";
                //            flags = newLaneWayAddress;
                //            var slotModel = dataContext.WmsBaseSlot.FirstOrDefault(m => m.SlotCode == item.slotCode);
                //            var lan = dataContext.WmsBaseSlot.Where(m => m.SlotLanewayId == slotModel.SlotLanewayId).ToList();
                //            if (slotModel.SlotRow > int.Parse(a[2]))
                //            {
                //                // 取最上面一排
                //                lan = lan.OrderBy(m => m.SlotCode).ToList();
                //                for (int i = 0; i < lan.Count; i++)
                //                {
                //                    var slot = dataContext.WmsBaseSlot.FirstOrDefault(m => m.SlotCode == lan[i].SlotCode);
                //                    if (slot.SlotStatus == 0)
                //                    {
                //                        if (i == lan.Count - 1)
                //                        {
                //                            newAddress = lan[lan.Count - 1].SlotCode;
                //                            break;
                //                        }
                //                        else
                //                        {
                //                            continue;
                //                        }
                //                    }
                //                    else
                //                    {
                //                        newAddress = lan[i - 1].SlotCode;
                //                        break;
                //                    }
                //                }
                //            }
                //            else
                //            {
                //                // 取最下面一排
                //                lan = lan.OrderByDescending(m => m.SlotCode).ToList();
                //                for (int i = 0; i < lan.Count; i++)
                //                {
                //                    var slot = dataContext.WmsBaseSlot.FirstOrDefault(m => m.SlotCode == lan[i].SlotCode);
                //                    if (slot.SlotStatus == 0)
                //                    {
                //                        if (i == lan.Count - 1)
                //                        {
                //                            newAddress = lan[lan.Count - 1].SlotCode;
                //                            break;
                //                        }
                //                        else
                //                        {
                //                            continue;
                //                        }
                //                    }
                //                    else
                //                    {
                //                        newAddress = lan[i - 1].SlotCode;
                //                        break;
                //                    }
                //                }
                //            }
                //            //添加回移任务
                //            AddHyTask(oldAddress, newAddress, newLaneWayAddress, oldSlot.SlotLanewayId, slotOut, billCode);
                //            refLanWayId = slotModel.SlotLanewayId;
                //            refLanOutCode = newLaneWayAddress;
                //            //9:锁定储位
                //            var updateSlot = dataContext.WmsBaseSlot.Where(m => m.SlotLanewayId == slotModel.SlotLanewayId).ToList();
                //            var newAddressRow = dataContext.WmsBaseSlot.FirstOrDefault(m => m.SlotCode == newAddress);
                //            if (newAddressRow.SlotRow > int.Parse(a[2]))
                //            {
                //                updateSlot = updateSlot.Where(m => m.SlotRow < newAddressRow.SlotRow && m.SlotRow > int.Parse(a[2])).OrderBy(m => m.SlotCode).ToList();
                //            }
                //            else
                //            {
                //                updateSlot = updateSlot.Where(m => m.SlotRow > newAddressRow.SlotRow && m.SlotRow < int.Parse(a[2])).OrderByDescending(m => m.SlotCode).ToList();
                //            }
                //            foreach (var source in updateSlot)
                //            {
                //                if (source.SlotCode == newAddress)
                //                {
                //                    continue;
                //                }
                //                if (source.SlotStatus == 0)
                //                {
                //                    source.SlotStatus = 8;
                //                }
                //            }
                //            if (updateSlot.Count <= 0)
                //            {
                //                refLanWayId = "";
                //                refLanOutCode = "";
                //            }
                //            dataContext.SubmitChanges();
                //            return newAddress;
                //        }
                //    }
                //}
                return newAddress;
                #endregion
        }
        /// <summary>
        /// 获取移库合适的储位 密集库
        /// </summary>
        /// <param name="laneWayId">合适组的巷道号</param>
        /// <param name="location">分配储位</param>
        /// <returns>true:存在合适储位   False:不存在合适储位</returns>
        private bool GetBecomingLocation(string laneWayId, ref string location)
        {
            bool bl = false;
            // 循环判断当前组是否有剩余储位
            string sqlString = string.Empty;
            location = "";
            // 判断储位组是否有空储位   关联库存明细表可防止储位状态不准确避免造成满入异常//not in ('1','2','4','6','7','8')
            sqlString = $"select LocatNo,Column,AisleOne from SysStorageLocat where RoadwayNo = {laneWayId} and Status in ('0') and LocatNo not in (select LocatNo from DataStockDetail where RoadwayNo = { laneWayId}) order by Row;";
            var slotModel =Db.SqlQueryable<LocateInfo>(sqlString).ToList();
            if (slotModel.Count == 0)
            {
                bl = false;
            }
            else  // 存在空储位
            {
                // 判断当前组合适的储位地址
                var numstr = slotModel[0].AisleOne.Substring(4,2);
                int aisleRow = int.Parse(numstr);
                if (slotModel[0].Column > aisleRow)
                {
                    // 取最上面一排
                    location = slotModel[0].LocatNo;
                }
                else
                {
                    // 取最下面一排
                    location = slotModel[slotModel.Count - 1].LocatNo;
                }
                bl = true;
            }
            return bl;
        }
        private class addreClass
        {
            public string slotCode { get; set; }
            public int distNum { get; set; }
        }
        public class LocateInfo
        {
            public string LocatNo { get; set; }
            public int Column { get; set; }
            public string AisleOne { get; set; }
        }
        #endregion
        #endregion
        //------------------------------------------------------------------
@@ -4289,727 +6253,7 @@
        }
        #endregion
        #region 自动分配、取消分配、获取手动分配的数据源、手动分配
        // 判断是否是跨批出库
        public bool IsCrossLotNo(string soNo)
        {
            try
            {
                //方法返回结果:bl
                var bl = true;
                //查询单据信息
                var notice = Db.Queryable<BllExportNotice>().First(m=>m.SONo == soNo && m.IsDel == "0");
                //判断单据类型  成品出库、领料出库(其它类型跳出此方法)
                if (notice.Type!="0" && notice.Type!="1")
                {
                    return bl;
                }
                //查询到当前单据下的出库单明细信息
                var noticeDetail = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList();
                //库存总表信息
                var data = Db.Queryable<DataStock>().Where(m => m.IsDel == "0").ToList();
                //库存明细中检验合格批次集合
                var dataDetail = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.InspectStatus == "1").GroupBy(g => g.LotNo).Select(s => s.LotNo).ToList();
                //库存明细表信息
                var dataBoxInfo = Db.Queryable<DataBoxInfo>().Where(m => m.IsDel == "0").ToList();
                //循环单据明细信息
                foreach (var item in noticeDetail)
                {
                    //验证先进先出原则
                    //获取当前物料的所有批次信息(排除单据的批次,防止单据所在批次锁定数量后验证小于等于0)
                    var forData = data.Where(m => m.SkuNo == item.SkuNo
                    && m.LotNo != item.LotNo && (m.Qty - m.FrozenQty - m.LockQty) > 0
                    && dataDetail.Contains(m.LotNo)).Select(m=>m.LotNo).ToList();
                    forData.Add(item.LotNo);  //集合添加单据的批次
                    //获取排序后的第一个批次
                    var firstLotNo = forData.OrderBy(m => m).First();
                    if (firstLotNo != item.LotNo)
                    {
                        bl = false;
                        break;
                    }
                    //验证效期优先原则
                    var forDataBox = dataBoxInfo.Where(m => m.SkuNo == item.SkuNo && m.LotNo != item.LotNo && m.Qty > 0).ToList();
                    //获取当前单据批次的最近效期
                    var expirationTimedt = dataBoxInfo.Where(m => m.SkuNo == item.SkuNo
                    && m.LotNo == item.LotNo && m.Qty > 0).ToList();
                    if (expirationTimedt.Count > 0)
                    {
                        var expirationTime = expirationTimedt.OrderBy(m => m.ExpirationTime).Select(m => m.ExpirationTime).First();
                        //获取库存中其它批次效期大于当前单据批次的效期数量
                        var num = forDataBox.Count(m => m.ExpirationTime > expirationTime);
                        //判断是否大于0
                        if (num > 0)
                        {
                            bl = false;
                            break;
                        }
                    }
                    else
                    {
                        var dataDetailtime = Db.Queryable<DataStockDetail>().Where(m => m.IsDel == "0" && m.InspectStatus == "1").
                            Where(m => m.SkuNo == item.SkuNo
                            && m.LotNo == item.LotNo && m.Qty > 0)
                            .OrderBy(m => m.ExpirationTime)
                            .Select(m => m.ExpirationTime).First();
                        var num = forDataBox.Count(m => m.ExpirationTime > dataDetailtime);
                        //判断是否大于0
                        if (num > 0)
                        {
                            bl = false;
                            break;
                        }
                    }
                }
                return bl;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        //自动分配
        public bool AutoAllot(string soNo, int userId)
        {
            try
            {
                #region 判断条件(出库单、出库单明细)
                //出库单
                var notice = Db.Queryable<BllExportNotice>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList().FirstOrDefault();
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                if (notice.Status != "0" && notice.Status != "1")
                {
                    throw new Exception("参数异常,请检查状态是否为等待执行或部分分配;");
                }
                //出库单明细
                var detailList = Db.Queryable<BllExportNoticeDetail>().Where(m => m.IsDel == "0" && m.SONo == soNo && (m.AllotQty - m.Qty) <= 0).ToList();
                if (!detailList.Any())
                {
                    throw new Exception("未查询到符合分配条件的出库单据明细信息");
                }
                #endregion
                var exAllotList = new List<BllExportAllot>();
                var assign = new AllotSku();
                Db.BeginTran();
                try
                {
                    List<SoDetailInfo> soDetailList = new List<SoDetailInfo>();
                    foreach (var detail in detailList)
                    {
                        if (detail.AllotQty >= detail.Qty)
                        {
                            continue;
                        }
                        //还需要分配的数量
                        decimal needQty = detail.Qty - (detail.AllotQty == null? 0: decimal.Parse(detail.AllotQty.ToString()));
                        //库存明细 Status 0:待分配 1:部分分配  2:已分配
                        var stockDetail = Db.Queryable<DataStockDetail>().Where(m => m.SkuNo == detail.SkuNo && (m.Qty - m.FrozenQty - m.LockQty + m.InspectQty) > 0 && (m.Status == "0" || m.Status == "1") && m.IsDel == "0").ToList();
                        //判断单号是否指定批次
                        if (!string.IsNullOrWhiteSpace(detail.LotNo))
                        {
                            stockDetail = stockDetail.Where(m => m.SkuNo == detail.SkuNo && m.LotNo == detail.LotNo && m.IsDel == "0").ToList();
                        }
                        else
                        {
                            stockDetail = stockDetail.Where(m => m.SkuNo == detail.SkuNo && m.IsDel == "0" && string.IsNullOrWhiteSpace(m.LotNo)).ToList();
                        }
                        if (stockDetail.Count < 1)
                        {
                            throw new Exception("库存不足,无可出库库存");
                        }
                        //0:成品出库、1:领料出库、2:抽检出库、4:不合格品出库、6:代储出库、7:其他出库、 ///3:取样出库、5:中间品出库、8:寄存出库
                        if (notice.Type == "0" || notice.Type == "1" )//成品、领料出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "1").ToList();
                        }
                        else if (notice.Type == "2" )//抽检出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "0" || m.InspectStatus == "1" || m.InspectStatus == "2").ToList();
                        }
                        else if (notice.Type == "6" || notice.Type == "7" ) //代储、其它
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "0" || m.InspectStatus == "1").ToList();
                        }
                        else if (notice.Type == "4")//不合格出库
                        {
                            stockDetail = stockDetail.Where(m => m.InspectStatus == "2").ToList();
                        }
                        if (stockDetail.Sum(m=>m.Qty-m.LockQty) < needQty)
                        {
                            throw new Exception("库存明细数量不足");
                        }
                        #region 包装信息
                        var pNum = 0;//托盘物品数量
                        var bNum = 0;//箱物品数量
                        //公共方法获取包装数量
                        new Common().GetPackQtyInfo(detail.PackagNo,ref pNum,ref bNum);
                        #endregion
                        //取合适库存商品
                        Dictionary<int, decimal> stockQtyDic = new Dictionary<int, decimal>();//托出库物品数
                        var qty = 0m;
                        //分配货物
                        qty += assign.AllotPallets(stockDetail, needQty, pNum, bNum, stockQtyDic, detail.LotNo, detail.IsMixBox);
                        foreach (var sc in stockQtyDic)
                        {
                            var s = stockDetail.FirstOrDefault(m => m.Id == sc.Key);
                            //添加分配表信息
                            var allot = new BllExportAllot
                            {
                                SONo = notice.SONo,
                                WaveNo = "",
                                SODetailNo = detail.Id,
                                StockId = sc.Key,
                                LotNo = s.LotNo,
                                LotText = s.LotText,
                                SupplierLot = s.SupplierLot,
                                SkuNo = s.SkuNo,
                                SkuName = s.SkuName,
                                Standard = s.Standard,
                                PalletNo = s.PalletNo,
                                IsBale = detail.IsBale == "0" ? "0" : s.IsBale == "1" ? "0" : "1", //是否裹包
                                IsBelt = detail.IsBelt == "0" ? "0" : s.IsBelt == "1" ? "0" : "1", //是否打带
                                Qty = sc.Value,
                                CompleteQty = 0,
                                //BoxexQty = s.Qty, //箱内数量
                                Status = "0",
                                LogisticsId = notice.LogisticsId,
                                IsAdvance = "0",
                                OutMode = "",//出库口
                                CreateUser = userId,
                                CreateTime = DateTime.Now
                            };
                            exAllotList.Add(allot);
                            s.LockQty += stockQtyDic[s.Id];
                            if (s.LockQty == s.Qty)
                            {
                                s.Status = "2";
                            }
                            else
                            {
                                s.Status = "1";
                            }
                            var sd = Db.Updateable(s).UpdateColumns(it => new { it.LockQty, it.Status }).ExecuteCommand();
                        }
                        detail.AllotQty += qty;
                        detail.UpdateUser = userId;
                        detail.UpdateTime = DateTime.Now;
                        if (detail.Status == "0")
                        {
                            detail.Status = "1";
                        }
                        if (qty > detail.Qty)
                        {
                            //库存总表
                            var stock = Db.Queryable<DataStock>().First(d => d.IsDel == "0"
                            && d.SkuNo == detail.SkuNo
                            && d.LotNo == detail.LotNo);
                            stock.LockQty += qty-detail.Qty;
                            Db.Updateable(stock).ExecuteCommand();
                            //添加回传上游系统锁定数量更改代码
                            SoDetailInfo soDetail = new SoDetailInfo();
                            soDetail.OrderDetailCode = detail.OrderDetailCode;
                            soDetail.LockQty = qty - detail.Qty;
                            soDetail.LotNo = detail.LotNo;
                            soDetailList.Add(soDetail);
                        }
                    }
                    var mx = Db.Updateable(detailList).ExecuteCommand();
                    var fp = Db.Insertable(exAllotList).ExecuteCommand();
                    //修改分配单据的状态
                    if (notice.Status == "0" || notice.Status == "1")
                    {
                        var bl = 0;
                        var bl2 = 0;
                        foreach (var item in detailList)
                        {
                            if (item.AllotQty <= 0)
                            {
                                continue;
                            }
                            if (item.AllotQty < item.Qty)
                            {
                                bl = 1;
                            }
                            else
                            {
                                bl2 = 1;
                            }
                        }
                        switch (bl2)
                        {
                            case 1 when bl == 1:
                                notice.Status = "1";//证明部分分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 0 when bl == 1:
                                notice.Status = "1";//证明部分分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 1 when bl == 0:
                                notice.Status = "2";//证明分配数量全部大于等于出库数量  修改为已分配
                                break;
                            case 0 when bl == 0:
                                //证明所有分配数量全部小于等于出库数量 不做修改
                                break;
                        }
                    }
                    notice.UpdateUser = userId;
                    notice.UpdateTime = DateTime.Now;
                    var zd = Db.Updateable(notice).ExecuteCommand();
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据",
                        notice.SONo, "分配", $"自动分配了单据号为{notice.SONo}的单据信息", userId);
                    if (zd > 0 && mx > 0 && fp > 0 && k)
                    {
                        #region 通过接口发送至erp
                        //系统对接后放开
                        /*var jsonData = JsonConvert.SerializeObject(soDetailList);
                        var response = HttpHelper.DoPost(url, jsonData, "库存锁定数量变更", "ERP");
                        var obj = JsonConvert.DeserializeObject<ErpModel>(response);//解析返回数据
                        if (obj.Success != 0)
                        {
                            throw new Exception("上传失败" + obj.Message);
                        }*/
                        #endregion
                        Db.CommitTran();
                        return true;
                    }
                    Db.RollbackTran();
                    return false;
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
            }
            catch (Exception e)
            {
                throw new Exception("自动分配失败:" + e.Message);
            }
        }
        //取消分配
        public bool CancelAllot(string soNo, int userId)
        {
            try
            {
                var notice = Db.Queryable<BllExportNotice>().Where(m => m.IsDel == "0" && m.SONo == soNo).ToList().FirstOrDefault();
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                if (notice.Status != "1" && notice.Status != "2")
                {
                    throw new Exception("参数异常,请检查状态是否为已分配或部分分配或来源是否是WMS");
                }
                //该单据的分配信息 Status 0:任务下发 1:待拣货 2:部分拣货 3:待回库 4:已完成
                var allotList = Db.Queryable<BllExportAllot>().Where(o => o.IsDel == "0" && o.SONo == soNo).ToList();
                //有已执行的分配数据不能取消
                if (allotList.Any(o => o.Status != "0"))
                {
                    throw new Exception("当前单据的分配信息已有执行中,不能取消分配");
                }
                List<SoDetailInfo> soDetailList = new List<SoDetailInfo>();
                //开启事务
                Db.BeginTran();
                try
                {
                    //查询分配的明细
                    var detail = Db.Queryable<BllExportNoticeDetail>().Where(d => d.SONo == soNo && d.AllotQty > 0 && d.IsDel == "0").ToList();
                    foreach (var d in detail)
                    {
                        var orders = allotList.Where(o => o.SODetailNo == d.Id).ToList();
                        foreach (var o in orders)
                        {
                            var pq = Db.Queryable<DataStockDetail>().Where(t => t.Id == o.StockId);
                            var pq2 = !string.IsNullOrWhiteSpace(o.LotNo) ? pq.Where(t => t.LotNo == o.LotNo).ToList() : pq.Where(t => string.IsNullOrWhiteSpace(t.LotNo)).ToList();
                            var pallet = pq2.FirstOrDefault();
                            if (pallet != null)
                            {
                                pallet.LockQty -= o.Qty;
                                pallet.Status = pallet.LockQty == 0 ? "0" : "1"; //如果锁定数量是0状态变更为待分配 否则为部分分配
                                Db.Updateable(pallet).ExecuteCommand();
                                //库存总表
                                //var stock = Db.Queryable<DataStock>().First(t => t.SkuNo == pallet.SkuNo && t.IsDel == "0");
                                //stock.LockQty -= o.Qty;
                                //Db.Updateable(stock).ExecuteCommand();
                            }
                        }
                        Db.Deleteable<BllExportAllot>(orders).ExecuteCommand();
                        if (d.AllotQty > d.Qty)
                        {
                            //库存总表
                            var stock = Db.Queryable<DataStock>().First(m => m.IsDel == "0" && m.SkuNo == d.SkuNo && m.LotNo == d.LotNo);
                            stock.LockQty -= (decimal)d.AllotQty - d.Qty;
                            Db.Updateable(stock).ExecuteCommand();
                            //添加回传上游系统锁定数量更改代码
                            SoDetailInfo soDetail = new SoDetailInfo();
                            soDetail.OrderDetailCode = d.OrderDetailCode;
                            soDetail.LockQty = (decimal)(d.Qty-d.AllotQty);
                            soDetail.LotNo = d.LotNo;
                            soDetailList.Add(soDetail);
                        }
                        d.AllotQty = 0;
                        d.Status = "0";
                        d.UpdateUser = userId;
                        d.UpdateTime = DateTime.Now;
                        //if (notice.Type == "1" || notice.Type == "5" || notice.Type == "6" || notice.Type == "7" || notice.Type == "8")//1:领料出库、
                        //{
                        //    if (d.IsIssueLotNo != "1")
                        //    {
                        //        d.LotNo = "";
                        //    }
                        //}
                    }
                    //查询当前单据是否已添加备料任务
                    if (notice.Type == "1")
                    {
                        var task = Db.Queryable<BllExportTimingTask>().First(m => m.IsDel == "0" && m.SoNo == soNo);
                        if (task!=null)
                        {
                            task.IsDel = "1";
                            task.UpdateUser = userId;
                            task.UpdateTime = DateTime.Now;
                            Db.Updateable(task).ExecuteCommand();
                        }
                    }
                    notice.Status = "0";
                    notice.UpdateUser = userId;
                    notice.UpdateTime = DateTime.Now;
                    Db.Updateable(detail).ExecuteCommand();
                    Db.Updateable(notice).ExecuteCommand();
                    //系统对接后放开
                    /*var jsonData = JsonConvert.SerializeObject(soDetailList);
                    var response = HttpHelper.DoPost(url, jsonData, "库存锁定数量变更", "ERP");
                    var obj = JsonConvert.DeserializeObject<ErpModel>(response);//解析返回数据
                    if (obj.Success != 0)
                    {
                        throw new Exception("上传失败" + obj.Message);
                    }*/
                    //添加操作日志记录
                    var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "取消分配", $"取消分配了单据号为{notice.SONo}的单据信息", userId);
                    Db.CommitTran();
                }
                catch (Exception e)
                {
                    Db.RollbackTran();
                    throw new Exception(e.Message);
                }
                return true;
            }
            catch (Exception e)
            {
                throw new Exception("取消分配失败" + e.Message);
            }
        }
        /// <summary>
        /// 维护出库单备注信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="demo"></param>
        /// <param name="userId"></param>
        public void EditNoticeDemo(int id, string demo, int userId)
        {
            try
            {
                var notice = Db.Queryable<BllExportNotice>().First(m => m.IsDel == "0" && m.Id == id);
                if (notice == null)
                {
                    throw new Exception("未查询到出库单据信息");
                }
                notice.Demo = demo + "".Trim();
                notice.UpdateUser = userId;
                notice.UpdateTime = DateTime.Now;
                int i = Db.Updateable(notice).ExecuteCommand();
                if (i > 0)
                {
                    //添加操作日志
                    new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "编辑", $"编辑了单据号为{notice.SONo}的备注信息", userId);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }
        //获取库存明细信息(出库单手动分配选择数据源)
        public List<StockDetailDto> GetHandOutList(int detailId, string houseNo, string roadwayNo, string locateNo, string msg, string palletNo)
        {
            try
            {
                var detail = Db.Queryable<BllExportNoticeDetail>().First(d => d.Id == detailId);
                #region 判断条件
                if (detail == null)
                {
                    throw new Exception("获取失败,未找到指定出库单!");
                }
                if (detail.Status != "0" && detail.Status != "1" && detail.AllotQty >= detail.Qty)
                {
                    throw new Exception("获取失败,出库单状态不是等待执行或分配中!");
                }
                if (detail.AllotQty >= detail.Qty)
                {
                    throw new Exception("获取失败,出库单已分配完成!");
                }
                var notice = Db.Queryable<BllExportNotice>().First(a => a.SONo == detail.SONo);
                if (notice == null)
                {
                    throw new Exception("获取失败,未找到指定出库单!");
                }
                if (notice.Status == "3" && detail.AllotQty >= detail.Qty || notice.Status == "4" || notice.Status == "5")
                {
                    throw new Exception("获取失败,出库单状态不允许!");
                }
                #endregion
                Expression<Func<DataStockDetail, bool>> item = Expressionable.Create<DataStockDetail>()
                    .AndIF(!string.IsNullOrWhiteSpace(houseNo), m => m.WareHouseNo == houseNo)
                    .AndIF(!string.IsNullOrWhiteSpace(roadwayNo), m => m.RoadwayNo == roadwayNo)
                    .AndIF(!string.IsNullOrWhiteSpace(locateNo), m => m.LocatNo == locateNo)
                    .AndIF(!string.IsNullOrWhiteSpace(palletNo), m => m.PalletNo == palletNo)
                    .AndIF(!string.IsNullOrWhiteSpace(msg),
                        m => m.SkuNo.Contains(msg.Trim())
                             || m.SkuName.Contains(msg.Trim())
                             || m.LocatNo.Contains(msg.Trim()))
                    .And(m => m.IsDel == "0" && m.SkuNo == detail.SkuNo && m.LotNo == detail.LotNo && (m.Status == "0" || m.Status == "1"))
                    .ToExpression();//注意 这一句 不能少
                var list = Db.Queryable<DataStockDetail>().Where(item).Select(a => new StockDetailDto
                {
                    Id = a.Id,
                    SkuNo = a.SkuNo,
                    SkuName = a.SkuName,
                    Standard = a.Standard,
                    LotNo = a.LotNo,
                    LotText = a.LotText,
                    SupplierLot = a.SupplierLot,
                    Qty = a.Qty - a.LockQty - a.FrozenQty,
                    LocatNo = a.LocatNo,
                    RoadwayNo = a.RoadwayNo,
                    PalletNo = a.PalletNo,
                    Demo = a.Demo,
                }).ToList();
                return list;
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }
        //手动分配出库单明细
        public void AddHandOutAllot(AddHandOutVm model, int userId)
        {
            try
            {
                #region 判断条件
                //数据验证
                var detail = Db.Queryable<BllExportNoticeDetail>().First(a => a.IsDel == "0" && a.Id == model.Id);
                if (detail == null)
                {
                    throw new Exception("操作失败,未找到指定出库单详情!");
                }
                if (detail.AllotQty >= detail.Qty || (detail.Status != "0" && detail.Status != "1"))
                {
                    throw new Exception("操作失败,出库单已分配完成!");
                }
                var notice = Db.Queryable<BllExportNotice>().First(a => a.IsDel == "0" && a.SONo == detail.SONo);
                if (notice == null)
                {
                    throw new Exception("操作失败,未找到指定出库单!");
                }
                if (notice.Status == "3" && detail.AllotQty >= detail.Qty || notice.Status == "4" || notice.Status == "5")
                {
                    throw new Exception("操作失败,出库单已分配完成!");
                }
                #endregion
                //单据明细需要的出库数量
                var needQty = detail.Qty - detail.AllotQty;
                //分配的出库数量
                var outQty = model.StockList.Select(s => s.Qty).ToList().Sum();
                if (outQty != needQty)
                {
                    throw new Exception("操作失败,出库数量与计划数量不一致!");
                }
                var stockIds = model.StockList.Select(a => a.StockId).ToList();
                //库存明细
                var stockList = Db.Queryable<DataStockDetail>().Where(a => stockIds.Contains(a.Id)).ToList();
                //分配信息
                var allots = Db.Queryable<BllExportAllot>().Where(m => m.IsDel == "0" && m.SODetailNo == detail.Id && m.Status == "0").ToList();
                //库存总表
                //var stockz = Db.Queryable<DataStock>().First(d => d.IsDel == "0" && d.SkuNo == detail.SkuNo && d.LotNo == detail.LotNo);
                var allotList = new List<BllExportAllot>();
                decimal outQtys = 0;
                foreach (var st in model.StockList)
                {
                    var stock = stockList.First(a => a.Id == st.StockId);
                    if (stock == null)
                    {
                        throw new Exception("操作失败,部分储位库存异常!");
                    }
                    if (st.Qty > (stock.Qty - stock.LockQty - stock.FrozenQty))     // 输入的数量 -  托盘上可用的数量(托盘上数量-锁定的数量-冻结的数量)
                    {
                        throw new Exception("操作失败,出库数量超出库存数量!");
                    }
                    var bl = allots.FirstOrDefault(m => m.StockId == st.StockId);
                    if (bl == null)
                    {
                        //添加分配表信息
                        var allot = new BllExportAllot
                        {
                            SONo = notice.SONo,
                            WaveNo = "",
                            SODetailNo = detail.Id,
                            StockId = st.StockId,
                            LotNo = stock.LotNo,
                            LotText = stock.LotText,
                            SupplierLot = stock.SupplierLot,
                            SkuNo = stock.SkuNo,
                            SkuName = stock.SkuName,
                            Standard = stock.Standard,
                            PalletNo = stock.PalletNo,
                            IsBale = stock.IsBale,
                            IsBelt = stock.IsBelt,
                            Qty = st.Qty,
                            CompleteQty = 0,
                            Status = "0",
                            LogisticsId = notice.LogisticsId,
                            IsAdvance = "0",
                            OutMode = "",//出库口
                            CreateUser = userId,
                            CreateTime = DateTime.Now
                        };
                        allotList.Add(allot);
                    }
                    else
                    {
                        bl.Qty += st.Qty;
                        Db.Updateable(bl).ExecuteCommand();
                    }
                    //库存明细
                    stock.LockQty += st.Qty;
                    stock.Status = stock.LockQty == stock.Qty ? "2" : "1";
                    //库存总表
                    //stockz.LockQty += st.Qty;
                    //Db.Updateable(stockz).ExecuteCommand();
                    Db.Updateable(stock).UpdateColumns(it => new { it.LockQty, it.Status }).ExecuteCommand();
                    outQtys += st.Qty;
                }
                Db.Insertable(allotList).ExecuteCommand();
                //修改单据明细
                detail.AllotQty += outQtys;
                detail.UpdateUser = userId;
                detail.UpdateTime = DateTime.Now;
                if (detail.Status == "0")
                {
                    detail.Status = "1";
                }
                Db.Updateable(detail).ExecuteCommand();
                var detailList = Db.Queryable<BllExportNoticeDetail>()
                    .Where(m => m.IsDel == "0" && m.SONo == notice.SONo).ToList();
                //修改出库单状态
                if (notice.Status == "0" || notice.Status == "1")
                {
                    decimal totalQty = 0;
                    decimal totalAllotQty = 0;
                    foreach (var item in detailList)
                    {
                        totalQty += item.Qty;
                        totalAllotQty += Convert.ToInt32(item.AllotQty);
                    }
                    if (totalAllotQty >= totalQty)
                    {
                        notice.Status = "2";//证明分配数量大于等于出库数量  修改为已分配
                    }
                    else if (totalAllotQty < totalQty && totalAllotQty > 0)
                    {
                        notice.Status = "1";//证明分配数量小于等于出库数量  修改为部分分配
                    }
                    Db.Updateable(notice).ExecuteCommand();
                }
                //添加操作日志记录
                var k = new OperationSOServer().AddLogOperationSo("出库作业", "出库单据", notice.SONo, "分配", $"手动分配了单据号为{notice.SONo}、物料:{detail.SkuNo}、批次:{detail.LotNo}的单据信息", userId);
                Db.CommitTran();
            }
            catch (Exception e)
            {
                Db.RollbackTran();
                throw new Exception(e.Message);
            }
        }
        #endregion
        /// <summary>
        /// 判断出库是否需要拆箱