using Admin.NET.Application.Common.FindEmptyLocationFactory; using Admin.NET.Application.Common; using Furion; using Furion.DatabaseAccessor; using Furion.DatabaseAccessor.Extensions; using Furion.DependencyInjection; using Furion.DynamicApiController; using Furion.FriendlyException; using iWare.Wms.Core; using iWare.Wms.Core.Enum; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Linq.Dynamic.Core; namespace iWare.Wms.Application { /// /// 出库管理 /// [ApiDescriptionSettings("仓库作业", Name = "IExWarehouse", Order = 100)] [Route("api/[Controller]")] [DisableOpLog] public class ExWarehouseService : IExWarehouseService, IDynamicApiController, ITransient { private readonly IRepository _wmsContainerRep; private readonly IRepository _wmsMaterialRep; private readonly IRepository _wmsMaterialContainerRep; private readonly IRepository _wmsAreaRep; private readonly IRepository _wmsPlaceRep; private readonly IRepository _wmsTaskRep; private readonly IRepository _wmsMaterialStockRep; private readonly IRepository _wmsContainerPlaceRep; private readonly IRepository _sysUser; private readonly IRepository _wareSite; private readonly IRepository _wmsPart; private readonly IRepository _v_ware_inventory_by_container; private readonly IRepository _wareTask; private readonly IRepository _wmsContainerType; private readonly IRepository _v_empty_location; private readonly IRepository _wareLocationVsContainer; private readonly IRepository _v_EmptyLocationRep; public ExWarehouseService( IRepository wmsContainerRep, IRepository wmsMaterialRep, IRepository wmsMaterialContainerRep, IRepository wmsAreaRep, IRepository wmsPlaceRep, IRepository wmsTaskRep, IRepository wmsMaterialStockRep, IRepository wmsContainerPlaceRep, IRepository sysUser, IRepository wareSite, IRepository wmsPart, IRepository v_ware_inventory_by_container, IRepository wareTask, IRepository wmsContainerType, IRepository v_empty_location, IRepository wareLocationVsContainer, IRepository v_EmptyLocationRep ) { _wmsContainerRep = wmsContainerRep; _wmsMaterialRep = wmsMaterialRep; _wmsMaterialContainerRep = wmsMaterialContainerRep; _wmsAreaRep = wmsAreaRep; _wmsPlaceRep = wmsPlaceRep; _wmsTaskRep = wmsTaskRep; _wmsMaterialStockRep = wmsMaterialStockRep; _wmsContainerPlaceRep = wmsContainerPlaceRep; _sysUser = sysUser; _wareSite = wareSite; _wmsPart = wmsPart; _v_ware_inventory_by_container = v_ware_inventory_by_container; _wareTask = wareTask; _wmsContainerType = wmsContainerType; _v_empty_location = v_empty_location; _wareLocationVsContainer = wareLocationVsContainer; _v_EmptyLocationRep = v_EmptyLocationRep; } /// /// 分页查询库存表 /// /// /// [HttpGet("page")] public async Task> Page([FromQuery] WmsMaterialStockSearch input) { //var wmsMaterialStocks = await _wmsMaterialStockRep.DetachedEntities // .Where(!string.IsNullOrEmpty(input.Materialno), u => EF.Functions.Like(u.MaterialNo, $"%{input.Materialno.Trim()}%")) // .Where(input.Materialtype != null, u => u.MaterialType == input.Materialtype) // .Where(!string.IsNullOrEmpty(input.Materialbatch), u => EF.Functions.Like(u.MaterialBatch, $"%{input.Materialbatch.Trim()}%")) // .Where(!string.IsNullOrEmpty(input.Materialname), u => EF.Functions.Like(u.MaterialName, $"%{input.Materialname.Trim()}%")) // .Where(!string.IsNullOrEmpty(input.Materialspec), u => EF.Functions.Like(u.MaterialSpec, $"%{input.Materialspec.Trim()}%")) // .Where(input.Inspectionmethod != null, u => u.InspectionMethod == input.Inspectionmethod) // .Where(input.Unittype != null, u => u.UnitType == input.Unittype) // .Where(input.Unitno != null, u => u.UnitNo == input.Unitno) // .Where(u => u.StockNumber != 0) // .Where(!string.IsNullOrEmpty(input.Placecode), u =0> u.PlaceCode == input.Placecode) // .Where(!string.IsNullOrEmpty(input.Containercode), u => u.ContainerCode == input.Containercode) // .OrderBy(PageInputOrder.OrderBuilder(input)) // .ProjectToType() // .ToADPagedListAsync(input.PageNo, input.PageSize); //获取登录用户 var contextUser = App.User; var userName = contextUser.Claims.Single(x => x.Type == "Account").Value; //获取登录用户所属线别 var lineType = await _sysUser.DetachedEntities.Where(u => u.Account == userName).Select(u => u.LineType).FirstOrDefaultAsync(); var lvms = await _v_ware_inventory_by_container.DetachedEntities .Where(!string.IsNullOrEmpty(input.Materialno), u => u.WareMaterialCode.Contains(input.Materialno)) .Where(!string.IsNullOrEmpty(input.Materialname), u => u.WareMaterialName.Contains(input.Materialname)) .Where(!string.IsNullOrEmpty(input.Placecode), u => u.WareLocationCode == input.Placecode) .Where(!string.IsNullOrEmpty(input.Containercode), u => u.WareContainerCode == input.Containercode) .Where(!string.IsNullOrEmpty(input.PartCode), u => u.PartCode == input.PartCode) .Where(!string.IsNullOrEmpty(input.PCPartCode), u => u.PartCode.Contains(input.PCPartCode)) .Where(lineType != null && lineType != LineTypeEnum.通用,u => u.LineType == lineType) .OrderBy(PageInputOrder.OrderBuilder(input)) .ProjectToType() .ToADPagedListAsync(input.PageNo, input.PageSize); return lvms; } /// /// 手动出库 /// /// /// [HttpPost("ManualWare")] public async Task ManualWare(ExManualWarehouseInput input) { if (string.IsNullOrEmpty(input.ToPlace)) { throw Oops.Oh("目标站台不能为空"); } if (string.IsNullOrEmpty(input.Containercode)) { throw Oops.Oh("小车编号不能为空"); } if (string.IsNullOrEmpty(input.Placecode)) { throw Oops.Oh("库位编号不能为空"); } //找库存 var balance = await _v_ware_inventory_by_container.DetachedEntities.Where(u => u.WareLocationCode == input.Placecode && u.WareContainerCode == input.Containercode && u.IsLocked == false).OrderBy(u => u.DeepcellNo).FirstOrDefaultAsync(); if (balance == null) { throw Oops.Oh($"根据小车{input.Containercode}和库位{input.Placecode}没有找到可用库存"); } if (balance.StockStatus != StockStatusEnum.在库) { throw Oops.Oh($"零件{input.Containercode}对应的端拾器{input.Placecode}没有可用库存"); } if (string.IsNullOrEmpty(input.ToPlace)) { throw Oops.Oh("目的地不能为空"); } var line = (LineTypeEnum)Enum.Parse(typeof(LineTypeEnum), input.ToPlace); var site = await _wareSite.DetachedEntities.Where(u => u.LineType == line).FirstOrDefaultAsync(); if (site == null) { throw Oops.Oh("生产线没有配置站台"); } // 创建任务 var tasknew = new WareTask { //OrderNo = input.OrderNo, TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(), //TaskName = wcsTask.TaskName, //TaskCategory = wcsTask.TaskType, TaskCategory = TaskCategoryEnum.出库任务, TaskDescribe = "", TaskPriority = 99, //TaskState = 0, TaskState = (int)TaskStateEnum.未执行, //TaskType = wcsTask.TaskType, FromLocationCode = balance.WareLocationCode, ToLocationCode = site.Code, ContainerCode = balance.WareContainerCode, Lane = balance.Lane, ContainerType = 0, PartCode = input.PartCode, BeginTime = DateTimeOffset.Now, }; var cvms = await _wmsContainerPlaceRep.Where(u => u.WareContainerCode == balance.WareContainerCode).ToListAsync(); foreach (var item in cvms) { item.StockStatus = StockStatusEnum.出库中; item.IsLocked = true; } using (var tran = await _wareTask.Database.BeginTransactionAsync()) { try { if (tasknew != null) { await _wareTask.InsertAsync(tasknew); } if (cvms != null && cvms.Count > 0) { await _wmsContainerPlaceRep.UpdateAsync(cvms); } await tran.CommitAsync(); } catch { await tran.RollbackAsync(); } } } /// /// 自动出库 /// /// /// [HttpPost("AutoWare")] [AllowAnonymous] public async Task AutoWare(ExAutoWarehouseInput input) { LineTypeEnum? lineType = null; if (input.LineType == null) { var contextUser = App.User; var userName = contextUser.Claims.Single(x => x.Type == "Account").Value; //获取登录用户所属线别 lineType = await _sysUser.DetachedEntities.Where(u => u.Account == userName).Select(u => u.LineType).FirstOrDefaultAsync(); } else { lineType = input.LineType; } ////获取登录用户 //通过线别获取终点站台 if (lineType == null) { throw Oops.Oh("该登录用户没有配置线别"); } //通过零件号查找端拾器信息 var part = await _wmsPart.DetachedEntities.Where(u => u.PartCode == input.PartNo && u.LineType == lineType).FirstOrDefaultAsync(); if (part == null && input.LineType == null) { throw Oops.Oh("生产线没有该零件信息"); } LineTypeEnum? line = null; if (input.LineType != null) { line = (LineTypeEnum)Enum.Parse(typeof(LineTypeEnum), Convert.ToString(input.LineType)); if (line != LineTypeEnum.A线 && line != LineTypeEnum.B线 && line != LineTypeEnum.C线) { throw Oops.Oh("请输入正确的线别"); } } var site = await _wareSite.Where(u => u.LineType == (line != null ? line : lineType)).FirstOrDefaultAsync(); if (site == null) { throw Oops.Oh($"线别{part.LineType}没有配置站台信息"); } //找库存 var balance = await _v_ware_inventory_by_container.DetachedEntities.Where(u => u.PartCode == input.PartNo && u.WareMaterialCode == part.MaterialCode && u.IsLocked == false).OrderBy(u => u.DeepcellNo).FirstOrDefaultAsync(); if (balance == null) { throw Oops.Oh($"零件{input.PartNo}对应的端拾器没有可用库存"); } if (balance.StockStatus != StockStatusEnum.在库) { throw Oops.Oh($"零件{input.PartNo}对应的端拾器没有可用库存"); } // 创建任务 var tasknew = new WareTask { //OrderNo = input.OrderNo, TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(), //TaskName = wcsTask.TaskName, //TaskCategory = wcsTask.TaskType, TaskCategory = TaskCategoryEnum.出库任务, TaskDescribe = "", TaskPriority = 99, //TaskState = 0, TaskState = (int)TaskStateEnum.未执行, //TaskType = wcsTask.TaskType, FromLocationCode = balance.WareLocationCode, ToLocationCode = site.Code, ContainerCode = balance.WareContainerCode, Lane = balance.Lane, ContainerType = 0, PartCode = input.PartNo, BeginTime = DateTimeOffset.Now, }; var cvms = await _wmsContainerPlaceRep.Where(u => u.WareContainerCode == balance.WareContainerCode).ToListAsync(); foreach (var item in cvms) { item.StockStatus = StockStatusEnum.出库中; item.IsLocked = true; } using (var tran = await _wareTask.Database.BeginTransactionAsync()) { try { if (tasknew != null) { await _wareTask.InsertAsync(tasknew); } if (cvms != null && cvms.Count > 0) { await _wmsContainerPlaceRep.UpdateAsync(cvms); } await tran.CommitAsync(); } catch { await tran.RollbackAsync(); } } } /// /// 入库 /// /// /// [HttpPost("AutoInWare")] [AllowAnonymous] public async Task AutoInWare(ExAutoWarehouseInput input) { if (string.IsNullOrEmpty(input.RealLocationCode)) { //throw Oops.Oh("目标库位不能为空"); //如果库位是空的,重新找一下库位 FindEmptyLocationServiceHandle handle = null; handle = FindEmptyLocationServiceFactory.GetHandle(MeterialType.物料, _v_EmptyLocationRep, _wmsPlaceRep, _wareTask, _wmsContainerPlaceRep, _wmsContainerRep, _wmsContainerType, _v_ware_inventory_by_container, input.RealLocationCode, ""); var emtpyLocation = handle.MainFindEmptyLocation(); if (emtpyLocation == null) { throw Oops.Oh("目前没有空库位存放!"); } input.RealLocationCode = emtpyLocation.PlaceCode; } else { var place = await _wmsPlaceRep.DetachedEntities.Where(u => u.PlaceCode == input.RealLocationCode).FirstOrDefaultAsync(); if (place == null) { throw Oops.Oh("目标库位不能是" + input.RealLocationCode); } var lvc = await _wareLocationVsContainer.DetachedEntities.Where(u => u.WareLocationCode == input.RealLocationCode).FirstOrDefaultAsync(); if (lvc != null)//目标有货 { if (lvc.IsEmptyContainer == true) { throw Oops.Oh("配置的目标库位需要移库,请稍等"); } else { throw Oops.Oh("目标库位有货,请处理"); } } input.RealLocationCode = place.PlaceCode; } ////获取登录用户 //var contextUser = App.User; //var userName = contextUser.Claims.Single(x => x.Type == "Account").Value; ////获取登录用户所属线别 //var lineType = await _sysUser.DetachedEntities.Where(u => u.Account == userName).Select(u => u.LineType).FirstOrDefaultAsync(); ////通过线别获取终点站台 //if (lineType == null) //{ // throw Oops.Oh("该登录用户没有配置线别"); //} var vi = await _v_ware_inventory_by_container.DetachedEntities.Where(u => u.PartCode == input.PartCode && u.WareContainerCode == input.Containercode).FirstOrDefaultAsync(); if (vi == null) { throw Oops.Oh("没有查询到对应的信息"); } if (vi.StockStatus == StockStatusEnum.在库) { throw Oops.Oh("对应端拾器已经在库"); } //通过零件号查找端拾器信息 var part = await _wmsPart.DetachedEntities.Where(u => u.PartCode == vi.PartCode).FirstOrDefaultAsync(); if (part == null && input.LineType == null) { throw Oops.Oh("零件没有配置对应的端拾器信息"); } LineTypeEnum? line = null; if (input.ToPlace != null) { line = (LineTypeEnum)Enum.Parse(typeof(LineTypeEnum), Convert.ToString(input.ToPlace)); if (line != LineTypeEnum.A线 && line != LineTypeEnum.B线 && line != LineTypeEnum.C线) { throw Oops.Oh("请输入正确的线别"); } } var site = await _wareSite.Where(u => u.LineType == (line != null ? line : part.LineType)).FirstOrDefaultAsync(); if (site == null) { throw Oops.Oh($"线别{part.LineType}没有配置站台信息"); } //找库存 //var balance = await _v_ware_inventory_by_container.DetachedEntities.Where(u => u.PartCode == input.PartNo && u.IsLocked == false).OrderBy(u => u.DeepcellNo).FirstOrDefaultAsync(); //if (balance == null) //{ // throw Oops.Oh($"零件{input.PartNo}对应的端拾器没有可用库存"); //} //if (balance.StockStatus != StockStatusEnum.在库) //{ // throw Oops.Oh($"零件{input.PartNo}对应的端拾器没有可用库存"); //} // 创建任务 var tasknew = new WareTask { //OrderNo = input.OrderNo, TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(), //TaskName = wcsTask.TaskName, //TaskCategory = wcsTask.TaskType, TaskCategory = TaskCategoryEnum.入库任务, TaskDescribe = "", TaskPriority = 99, //TaskState = 0, TaskState = (int)TaskStateEnum.未执行, //TaskType = wcsTask.TaskType, FromLocationCode = site.Code, ToLocationCode = input.RealLocationCode, ContainerCode = vi.WareContainerCode, Lane = vi.Lane, ContainerType = 0, PartCode = vi.PartCode, BeginTime = DateTimeOffset.Now, }; var cvms = await _wmsContainerPlaceRep.Where(u => u.WareContainerCode == vi.WareContainerCode).ToListAsync(); foreach (var item in cvms) { item.StockStatus = StockStatusEnum.出库中; item.IsLocked = true; } using (var tran = await _wareTask.Database.BeginTransactionAsync()) { try { if (tasknew != null) { await _wareTask.InsertAsync(tasknew); } if (cvms != null && cvms.Count > 0) { await _wmsContainerPlaceRep.UpdateAsync(cvms); } await tran.CommitAsync(); } catch { await tran.RollbackAsync(); } } } /// /// 获取移库空库位 /// /// /// [HttpGet("GetRemoveLocation")] public async Task GetRemoveLocation([FromQuery] ExManualWarehouseInput input) { var container = await _wmsContainerRep.DetachedEntities.Where(u => u.ContainerCode == input.Containercode).FirstOrDefaultAsync(); if (container == null) { throw Oops.Oh("查询小车为空"); } var containerType = await _wmsContainerType.DetachedEntities.Where(u => u.WareContainerTypeCode == container.ContainerTypeCode).FirstOrDefaultAsync(); if (containerType == null) { throw Oops.Oh("查询小车类型失败"); } var location = await _v_empty_location.DetachedEntities.Where(u => u.WareLocationTypeCode == containerType.LocationType) .Select(u => new { code = u.PlaceCode }).ToListAsync(); return location; } /// /// 手动移库任务 /// /// /// [HttpPost("MoveWare")] public async Task MoveWare(ExManualWarehouseInput input) { if (string.IsNullOrEmpty(input.ToPlace)) { throw Oops.Oh("目标站台不能为空"); } if (string.IsNullOrEmpty(input.Containercode)) { throw Oops.Oh("小车编号不能为空"); } if (string.IsNullOrEmpty(input.Placecode)) { throw Oops.Oh("库位编号不能为空"); } var container = await _wmsContainerRep.Where(u => u.ContainerCode == input.Containercode).FirstOrDefaultAsync(); if (container == null) { throw Oops.Oh("查询小车为空"); } var containerType = await _wmsContainerType.DetachedEntities.Where(u => u.WareContainerTypeCode == container.ContainerTypeCode).FirstOrDefaultAsync(); if (containerType == null) { throw Oops.Oh("查询小车类型失败"); } var cvm = await _v_ware_inventory_by_container.DetachedEntities.Where(u => u.WareContainerCode == input.Containercode).FirstOrDefaultAsync(); if (cvm == null) { throw Oops.Oh("库存查询错误"); } if (cvm.StockStatus != StockStatusEnum.在库) { throw Oops.Oh("库存不是在库"); } var location = await _wmsPlaceRep.DetachedEntities.Where(u => u.PlaceCode == input.Placecode).FirstOrDefaultAsync(); if (location == null) { throw Oops.Oh("源库位查询错误"); } if (location.WareLocationTypeCode != containerType.LocationType) { throw Oops.Oh("库位校验错误,选定的库位不是小车的可入库位"); } if (location.DeepcellNo == (int)DeepcellNoEnum.远伸) { //选择库存远伸要判断一下近伸有没有货 var nearLocation = await _wmsPlaceRep.DetachedEntities.Where(u => u.UnionCode == location.UnionCode && u.DeepcellNo == (int)DeepcellNoEnum.近伸).FirstOrDefaultAsync(); if (nearLocation == null) { throw Oops.Oh("近伸库位查询错误"); } var lvc = await _wareLocationVsContainer.DetachedEntities.Where(u => u.WareLocationCode == nearLocation.PlaceCode).FirstOrDefaultAsync(); if (lvc != null) { throw Oops.Oh("不能进行移库,因为选择的库存近伸有货"); } } var toLocation = await _v_empty_location.DetachedEntities.Where(u => u.PlaceCode == input.ToPlace).FirstOrDefaultAsync(); if (toLocation == null) { throw Oops.Oh("目标库位查询错误"); } if (toLocation.DeepcellNo == DeepcellNoEnum.远伸) { //选择库存远伸要判断一下近伸有没有货 var nearLocation = await _v_empty_location.DetachedEntities.Where(u => u.UnionCode == toLocation.UnionCode && u.DeepcellNo == (int)DeepcellNoEnum.近伸).FirstOrDefaultAsync(); if (nearLocation == null) { throw Oops.Oh("近伸库位查询错误"); } //var lvc = await _wareLocationVsContainer.DetachedEntities.Where(u => u.WareLocationCode == nearLocation.PlaceCode).FirstOrDefaultAsync(); //if (lvc != null) //{ // throw Oops.Oh("不能进行移库,因为选择的目标库位近伸有货"); //} toLocation = nearLocation; } //小车绑定库位更换 container.RealLocationCode = toLocation.PlaceCode; // 创建任务 var tasknew = new WareTask { //OrderNo = input.OrderNo, TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(), //TaskName = wcsTask.TaskName, //TaskCategory = wcsTask.TaskType, TaskCategory = TaskCategoryEnum.移库任务, TaskDescribe = "", TaskPriority = 99, //TaskState = 0, TaskState = (int)TaskStateEnum.未执行, //TaskType = wcsTask.TaskType, FromLocationCode = input.Placecode, ToLocationCode = toLocation.PlaceCode, ContainerCode = input.Containercode, Lane = location.Line, ContainerType = 0, PartCode = input.PartCode, BeginTime = DateTimeOffset.Now, }; var cvms = await _wmsContainerPlaceRep.Where(u => u.WareContainerCode == input.Containercode).ToListAsync(); foreach (var item in cvms) { item.StockStatus = StockStatusEnum.移库中; item.IsLocked = true; } using (var tran = await _wareTask.Database.BeginTransactionAsync()) { try { if (tasknew != null) { await _wareTask.InsertAsync(tasknew); } if (cvms != null && cvms.Count > 0) { await _wmsContainerPlaceRep.UpdateAsync(cvms); } await _wmsContainerRep.UpdateAsync(container); await tran.CommitAsync(); } catch { await tran.RollbackAsync(); } } } } }