public async Task <ReelSupplyResultDto> Supply(ReelSupplyInputDto[] input)
        {
            ReelSupplyResultDto res = new ReelSupplyResultDto()
            {
                ErrorMsgs = new List <string>(), IsSuccess = true
            };

            List <ReelSupplyTemp> reelSupplyTemps = new List <ReelSupplyTemp>();

            await _repository.DeleteAsync(r => true);

            var la = await _repositorySL.GetAllListAsync(s => s.LightState != LightState.Off);

            foreach (var sl in la)
            {
                sl.LightState = LightState.Off;
                // await _repositorySL.UpdateAsync(sl);
            }
            CurrentUnitOfWork.SaveChanges();
            // 查询备损数量
            var readyLossQty = SettingManager.GetSettingValueForTenant <int>("readyLossQty", AbpSession.TenantId.Value);//  int.Parse(_repositoryT.FirstOrDefault(c => c.TenantId == AbpSession.TenantId && c.Name == "readyLossQty").Value);

            // 查询提前预警天数
            var overdueDay = SettingManager.GetSettingValueForTenant <int>("overdueDay", AbpSession.TenantId.Value); //int.Parse(_repositoryT.FirstOrDefault(c => c.TenantId == AbpSession.TenantId && c.Name == "overdueDay").Value);

            // 查询强制先进先出天数
            var mustFifoDay = SettingManager.GetSettingValueForTenant <int>("mustFifoDay", AbpSession.TenantId.Value); //int.Parse(_repositoryT.FirstOrDefault(c => c.TenantId == AbpSession.TenantId && c.Name == "mustFifoDay").Value);

            // 补料调拨策略
            var reelSupplyMethodId = SettingManager.GetSettingValueForTenant("reelSupplyMethodId", AbpSession.TenantId.Value);// _repositoryT.FirstOrDefault(c => c.TenantId == AbpSession.TenantId && c.Name == "reelSupplyMethodId").Value;

            // 获取补料调拨策略
            var reelSupplyMethod = await _repositoryRMM.GetAllIncluding(r => r.OutStorages).FirstOrDefaultAsync(r => r.Id == reelSupplyMethodId);

            if (reelSupplyMethod == null)
            {
                res.ErrorMsgs.Add("未配置补料调拨策略");
                throw new LYException(res);
            }


            // 按备料单分组
            foreach (var item in input.GroupBy(r => r.ReadyMBillId))
            {
                // 查询当前备料单详细
                var readyNow = await _repositoryrb.FirstOrDefaultAsync(item.Key);

                if (readyNow == null)
                {
                    res.ErrorMsgs.Add("备料单[" + item.Key + "]不存在");

                    continue;
                }

                // 先假设没有关联的备料单信息
                var allReadys = new List <ReadyMBill>()
                {
                    readyNow
                };

                if (readyNow.ReReadyMBillId != null)
                {
                    // 查询备料单关联的所有备料单是否包含当前物料
                    allReadys = await _repositoryrb.GetAll().Where(r => r.ReReadyMBillId == readyNow.ReReadyMBillId).ToListAsync();
                }

                foreach (var pn in item)
                {
                    // 查询所有备料详细是否包含该物料
                    var pnInfo = await _repositoryrbd.GetAll().Where(r => allReadys.Select(rm => rm.Id).Contains(r.ReadyMBillId) && r.PartNoId == pn.PartNoId).FirstOrDefaultAsync();

                    if (pnInfo == null)
                    {
                        res.ErrorMsgs.Add("备料单[" + item.Key + "]及其合并的备料单不包含物料[" + pn + "]的备料信息");
                        continue;
                    }

                    // 查询物料基础信息

                    var mpn = await _repositorympn.FirstOrDefaultAsync(pn.PartNoId);

                    // 查询库存中该料号所有物料 在库存中挑料,分为两部分.一部分强制先进先出。一部分按数量挑选
                    var reels = _repositoryReel.GetAll().Where(r =>
                                                               r.StorageLocationId.Length > 0 &&                                                                                            // 有库位
                                                               r.IsActive &&                                                                                                                // 有效
                                                               r.PartNoId == pn.PartNoId &&                                                                                                 // 料号正确
                                                               reelSupplyMethod.OutStorages.Select(s => s.StorageId).Contains(r.StorageId)                                                  // 仓库正确
                                                               ).ToList()
                                .Where(r => r.MakeDate.AddDays(mpn.ShelfLife + r.ExtendShelfLife - overdueDay) > DateTime.Now && reelSupplyTemps.FirstOrDefault(s => s.Id == r.Id) == null) // 未过期 且未被挑料
                                .ToList();                                                                                                                                                  // 按d/c 进行先进先出排序

                    // && r.MakeDate.AddDays(mpn.ShelfLife + r.ExtendShelfLife - mustFifoDay) > DateTime.Now  // 必须先进先出
                    var nowDemandSendQty = pn.Qtys;


                    // 死循环挑料,库存料盘还有。且没挑够,且站位未发够
                    while (reels.Count > 0 && nowDemandSendQty > 0)
                    {
                        // 先挑选强制发料物料
                        var reel = reels.Where(r => r.MakeDate.AddDays(mpn.ShelfLife + r.ExtendShelfLife - mustFifoDay) > DateTime.Now).OrderBy(r => r.MakeDate).FirstOrDefault();

                        if (reel == null) // 没有强制先进先出
                        {
                            // 获取库存最大料盘数量
                            var maxQtyReel = reels.OrderBy(r => r.Qty).FirstOrDefault().Qty;

                            if (nowDemandSendQty > maxQtyReel)
                            {
                                // 当需求数大于库存最大料盘数量,按FIFO取同数量中物料
                                reel = reels.Where(r => r.Qty == maxQtyReel).OrderBy(r => r.MakeDate).FirstOrDefault();
                            }
                            else
                            {
                                // 当需求数小于库存最大料盘数量
                                //  1、先查询库存数量大于需求数且差距最小物料
                                reel = reels.Where(r => r.Qty > nowDemandSendQty).OrderBy(r => reel.Qty).FirstOrDefault();

                                if (reel == null)
                                {
                                    // 2、如果没有数量大于需求数物料,直接从最大包装开始拿料
                                    reel = reels.OrderByDescending(r => r.Qty).FirstOrDefault();
                                }
                            }
                        }

                        // 模拟添加发料临时表,且标记为已发
                        reelSupplyTemps.Add(new ReelSupplyTemp()
                        {
                            Id                   = reel.Id,
                            IsActive             = true,
                            PartNoId             = pn.PartNoId,
                            DemandQty            = pn.Qtys,
                            DemandSendQty        = pn.Qtys,
                            IsSend               = false,
                            Qty                  = reel.Qty,
                            SendQty              = reel.Qty,
                            StorageLocationId    = reel.StorageLocationId,
                            ReelMoveMethodId     = reelSupplyMethodId,
                            ReReadyMBillId       = readyNow.ReReadyMBillId == null ? readyNow.Id : readyNow.ReReadyMBillId,
                            ReadyMBillDetailedId = pnInfo.Id,
                            // SlotId = slot.Id
                        });

                        // 标记亮灯,真正的亮灯操作。移到专门的亮灯客户端
                        var sl = _repositorySL.Get(reel.StorageLocationId);
                        sl.LightState = LightState.On;
                        _repositorySL.Update(sl);



                        // 已发数量
                        // readySlotD.SendQty += reel.Qty;
                        // reel.SlotId = slot.Id;

                        // 更新站位数量
                        // slotQty -= reel.Qty;

                        // 移除当前料盘,让其不进入下一次挑料
                        reels.Remove(reel);

                        // 重新计算当前需求数
                        nowDemandSendQty = nowDemandSendQty - reel.Qty;
                    }
                }
            }

            // 最后进行亮灯

            foreach (var reelSupplyTemp in reelSupplyTemps)
            {
                await _repository.InsertAsync(reelSupplyTemp);
            }

            CurrentUnitOfWork.SaveChanges();

            // 亮灯
            var lights = _repositorySL.GetAllList(s => s.LightState == LightState.On);

            //小灯
            var simlights = lights.Select(l => new StorageLight()
            {
                ContinuedTime = 10, LightOrder = 1, MainBoardId = l.MainBoardId, RackPositionId = l.PositionId
            }).ToList();

            LightService.LightOrder(simlights);

            // 灯塔
            var houselights = simlights.Select(l => new HouseLight()
            {
                HouseLightSide = 1, LightOrder = 1, MainBoardId = l.MainBoardId
            }).Distinct().ToList();

            // await _notificationService.SendNotification("HouseOrder", houselights);
            LightService.HouseOrder(houselights);

            res.ErrorMsgs.Add("补料挑料成功" + (res.ErrorMsgs.Count > 0 ? "部分条目补料失败" : ""));
            res.IsSuccess = true;

            return(res);
        }
        public async Task <ICollection <BatchSlotListDto> > BatchEdit(BatchSlotDto batchSlot)
        {
            var res = new List <BatchSlotListDto>();

            // 查询机种
            var product = _repositoryMPN.FirstOrDefault(batchSlot.ProductId);

            if (product == null)
            {
                throw new LYException(1, "半成品料号" + batchSlot.ProductId + "不存在");
            }

            // 查询所有 线别
            var lines = _repositoryLine.GetAll().Where(l => l.Id.StartsWith(batchSlot.LineId));

            if (lines == null || lines.Count() < 1)
            {
                throw new LYException(2, "线别" + batchSlot.LineId + "不存在");
            }
            try
            {
                List <Slot> listSlot = new List <Slot>();

                // 将所有线别插入料表和Pin信息
                foreach (var line in lines)
                {
                    // 检查是否有Pin信息
                    var uph = _repositoryUPH.FirstOrDefault(u => u.ProductId == batchSlot.ProductId && u.LineId == line.Id);

                    if (uph == null)
                    {
                        _repositoryUPH.Insert(new UPH()
                        {
                            ProductId = batchSlot.ProductId,
                            LineId    = line.Id,
                            IsActive  = true,
                            Pin       = batchSlot.Pin,
                            Remark    = "料站表导入自动添加的UPH信息",
                            Meter     = 1,
                            Qty       = 999999
                        });
                    }
                    else
                    {
                        uph.Pin = batchSlot.Pin;
                    }
                    foreach (var slot in batchSlot.Slots)
                    {
                        // 判断物料是否存在
                        var mpn = _repositoryMPN.FirstOrDefault(slot.PartNoId);

                        if (mpn == null)
                        {
                            if (res.FirstOrDefault(s => s.Index == slot.Index) == null)
                            {
                                res.Add(slot);
                            }
                            continue;
                        }

                        // 查询是否有料站表
                        var dtSlot = _repositorySlot.FirstOrDefault(s =>
                                                                    s.BoardSide == batchSlot.BoardSide &&
                                                                    s.Machine == slot.Machine &&
                                                                    s.ProductId == batchSlot.ProductId &&
                                                                    s.LineId == line.Id &&
                                                                    s.Table == slot.Table &&
                                                                    s.PartNoId == slot.PartNoId &&
                                                                    s.SlotName == slot.SlotName);


                        if (dtSlot == null)
                        {
                            // 没有
                            listSlot.Add(new Slot()
                            {
                                BoardSide   = batchSlot.BoardSide,
                                Feeder      = slot.Feeder,
                                IsActive    = true,
                                LineId      = line.Id,
                                Machine     = slot.Machine,
                                PartNoId    = slot.PartNoId,
                                Version     = batchSlot.Version,
                                Table       = slot.Table,
                                SlotName    = slot.SlotName,
                                Side        = slot.Side,
                                Qty         = slot.Qty,
                                ProductId   = batchSlot.ProductId,
                                MachineType = slot.MachineType,
                                Location    = string.Join(",", slot.Location.Trim().Replace("\"", "").Replace("-", "").Split(' ', StringSplitOptions.RemoveEmptyEntries)
                                                          .Select(s => s.Trim().Split(':', StringSplitOptions.RemoveEmptyEntries).Length > 1 ?
                                                                  s.Trim().Split(':', StringSplitOptions.RemoveEmptyEntries)[1] :
                                                                  s.Trim().Split(':', StringSplitOptions.RemoveEmptyEntries)[0]).OrderBy(s => s)),
                                LineSide = slot.LineSide,
                                Index    = slot.Index
                            });
                        }
                        else
                        {
                            // 有

                            dtSlot.BoardSide   = batchSlot.BoardSide;
                            dtSlot.Feeder      = slot.Feeder;
                            dtSlot.IsActive    = true;
                            dtSlot.LineId      = line.Id;
                            dtSlot.Machine     = slot.Machine;
                            dtSlot.PartNoId    = slot.PartNoId;
                            dtSlot.Version     = batchSlot.Version;
                            dtSlot.Table       = slot.Table;
                            dtSlot.SlotName    = slot.SlotName;
                            dtSlot.Side        = slot.Side;
                            dtSlot.Qty         = slot.Qty;
                            dtSlot.ProductId   = batchSlot.ProductId;
                            dtSlot.MachineType = slot.MachineType;
                            dtSlot.Location    = string.Join(",", slot.Location.Trim().Replace("\"", "").Replace("-", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).OrderBy(s => s));
                            dtSlot.LineSide    = slot.LineSide;
                            dtSlot.Index       = slot.Index;
                            listSlot.Add(dtSlot);
                        }
                    }
                }

                foreach (var item in listSlot)
                {
                    _repositorySlot.InsertOrUpdate(item);
                }

                await CurrentUnitOfWork.SaveChangesAsync();

                // 将不在本次料表中的站位更新为无效
                // 查询该机种该线别该版本
                var NoActives = _repositorySlot.GetAll().Where(r => r.BoardSide == listSlot.FirstOrDefault().BoardSide&& r.ProductId == listSlot.FirstOrDefault().ProductId&& r.LineId == listSlot.FirstOrDefault().LineId&& !listSlot.Select(s => s.Id).Contains(r.Id)).ToArray();

                foreach (var item in NoActives)
                {
                    item.IsActive = false;
                    _repositorySlot.Update(item);
                }
            }
            catch (Exception ex)
            {
                throw new LYException(ex.Message, ex);
            }

            return(res);
        }