| | |
| | | using AutoMapper; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core.BaseRepository; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_DTO.Stock; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_StockService |
| | | { |
| | | /// <summary> |
| | | /// 库存信息服务实现类 |
| | | /// </summary> |
| | | public partial class StockInfoService : ServiceBase<Dt_StockInfo, IRepository<Dt_StockInfo>>, IStockInfoService |
| | | { |
| | | private readonly IMapper _mapper; |
| | | |
| | | /// <summary> |
| | | /// 获取库存信息仓储接口 |
| | | /// </summary> |
| | | public IRepository<Dt_StockInfo> Repository => BaseDal; |
| | | |
| | | public StockInfoService(IRepository<Dt_StockInfo> BaseDal, IMapper mapper) : base(BaseDal) |
| | | /// <summary> |
| | | /// 构造函数 |
| | | /// </summary> |
| | | /// <param name="baseDal">基础数据访问对象</param> |
| | | public StockInfoService(IRepository<Dt_StockInfo> baseDal) : base(baseDal) |
| | | { |
| | | _mapper = mapper; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取库存信息列表(出库日期小于当前时间且库存状态为入库完成的记录) |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | /// <returns>库存信息列表</returns> |
| | | public async Task<List<Dt_StockInfo>> GetStockInfoAsync() |
| | | { |
| | | return await BaseDal.QueryDataAsync(x => x.OutboundDate < DateTime.Now && x.StockStatus == StockStatusEmun.入库完成.GetHashCode()); |
| | | return await BaseDal.QueryDataAsync(x => |
| | | x.OutboundDate < DateTime.Now && |
| | | x.StockStatus == StockStatusEmun.入库完成.GetHashCode()); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取库存信息列表(出库日期小于当前时间且库存状态为入库完成的记录,且仓库ID匹配) |
| | | /// </summary> |
| | | /// <param name="WarehouseId"></param> |
| | | /// <returns></returns> |
| | | public async Task<List<Dt_StockInfo>> GetStockInfoAsync(int WarehouseId) |
| | | /// <param name="warehouseId">仓库ID</param> |
| | | /// <returns>库存信息列表</returns> |
| | | public async Task<List<Dt_StockInfo>> GetStockInfoAsync(int warehouseId) |
| | | { |
| | | return await BaseDal.QueryDataAsync(x => x.OutboundDate < DateTime.Now && x.StockStatus == StockStatusEmun.入库完成.GetHashCode() && x.WarehouseId == WarehouseId); |
| | | return await BaseDal.QueryDataAsync(x => |
| | | x.OutboundDate < DateTime.Now && |
| | | x.StockStatus == StockStatusEmun.入库完成.GetHashCode() && |
| | | x.WarehouseId == warehouseId); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取库存信息(根据托盘码查询) |
| | | /// </summary> |
| | | /// <param name="PalletCode"></param> |
| | | /// <returns></returns> |
| | | public async Task<Dt_StockInfo> GetStockInfoAsync(string PalletCode) |
| | | /// <param name="palletCode">托盘编码</param> |
| | | /// <returns>库存信息</returns> |
| | | public async Task<Dt_StockInfo> GetStockInfoAsync(string palletCode) |
| | | { |
| | | return await BaseDal.QueryFirstAsync(x => x.PalletCode == PalletCode); |
| | | return await BaseDal.QueryDataNavFirstAsync(x => x.PalletCode == palletCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 更新库存数据 |
| | | /// </summary> |
| | | /// <param name="stockInfo"></param> |
| | | /// <returns></returns> |
| | | /// <param name="stockInfo">库存信息对象</param> |
| | | /// <returns>更新是否成功</returns> |
| | | public async Task<bool> UpdateStockAsync(Dt_StockInfo stockInfo) |
| | | { |
| | | return await BaseDal.UpdateDataAsync(stockInfo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 检索指定托盘在给定位置的库存详细信息 |
| | | /// </summary> |
| | | /// <param name="palletCode">托盘编码</param> |
| | | /// <param name="locationCode">货位编码</param> |
| | | /// <returns>库存信息</returns> |
| | | public async Task<Dt_StockInfo> GetStockInfoAsync(string palletCode, string locationCode) |
| | | { |
| | | return await BaseDal.QueryFirstAsync(x => x.PalletCode == palletCode && x.LocationCode == locationCode); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取仓库3D布局数据 |
| | | /// </summary> |
| | | /// <param name="warehouseId">仓库ID</param> |
| | | /// <returns>3D布局DTO</returns> |
| | | public async Task<Stock3DLayoutDTO> Get3DLayoutAsync(int warehouseId) |
| | | { |
| | | // 1. 查询仓库信息 |
| | | var warehouse = await Repository.Change<Dt_Warehouse>().GetFirstAsync(x => x.Id == warehouseId); |
| | | |
| | | // 2. 查询该仓库所有货位 |
| | | var locations = await Repository.Change<Dt_LocationInfo>().GetListAsync(x => x.WarehouseId == warehouseId); |
| | | |
| | | // 3. 查询该仓库所有库存信息(包含Details导航属性) |
| | | var stockInfos = await Repository.Change<Dt_StockInfo>().Includes(x => x.Details).GetListAsync(x => x.WarehouseId == warehouseId); |
| | | |
| | | // 4. 提取物料编号和批次号列表(去重) |
| | | var materielCodeList = stockInfos |
| | | .SelectMany(s => s.Details) |
| | | .Select(d => d.MaterielCode) |
| | | .Where(c => !string.IsNullOrEmpty(c)) |
| | | .Distinct() |
| | | .ToList(); |
| | | |
| | | var batchNoList = stockInfos |
| | | .SelectMany(s => s.Details) |
| | | .Select(d => d.BatchNo) |
| | | .Where(b => !string.IsNullOrEmpty(b)) |
| | | .Distinct() |
| | | .ToList(); |
| | | |
| | | // 5. 创建库存字典用于快速查找(以LocationId为键) |
| | | var stockDict = stockInfos.ToDictionary(s => s.LocationId, s => s); |
| | | |
| | | // 6. 映射每个货位到Location3DItemDTO |
| | | const float defaultMaxCapacity = 100f; |
| | | var locationItems = locations.Select(loc => |
| | | { |
| | | var item = new Location3DItemDTO |
| | | { |
| | | LocationId = loc.Id, |
| | | LocationCode = loc.LocationCode, |
| | | Row = loc.Row, |
| | | Column = loc.Column, |
| | | Layer = loc.Layer, |
| | | LocationStatus = loc.LocationStatus, |
| | | MaxCapacity = defaultMaxCapacity |
| | | }; |
| | | |
| | | // 尝试从库存字典中获取库存信息 |
| | | if (stockDict.TryGetValue(loc.Id, out var stockInfo)) |
| | | { |
| | | item.PalletCode = stockInfo.PalletCode; |
| | | item.StockQuantity = stockInfo.Details.Sum(d => d.StockQuantity); |
| | | |
| | | // 获取第一个明细的物料信息(如果存在) |
| | | var firstDetail = stockInfo.Details.FirstOrDefault(); |
| | | if (firstDetail != null) |
| | | { |
| | | item.MaterielCode = firstDetail.MaterielCode; |
| | | item.MaterielName = firstDetail.MaterielName; |
| | | item.BatchNo = firstDetail.BatchNo; |
| | | } |
| | | |
| | | // 计算库存状态 |
| | | var ratio = item.MaxCapacity > 0 ? item.StockQuantity / item.MaxCapacity : 0; |
| | | if (ratio >= 0.9f) |
| | | item.StockStatus = 3; // 已满 (FULL) |
| | | else if (ratio >= 0.1f) |
| | | item.StockStatus = 1; // 有货 (HAS_STOCK) |
| | | else if (ratio > 0) |
| | | item.StockStatus = 2; // 库存紧张 (LOW_STOCK) |
| | | else |
| | | item.StockStatus = 0; // 无货 (EMPTY) |
| | | } |
| | | else |
| | | { |
| | | item.StockStatus = 0; // 无货 (EMPTY) |
| | | item.StockQuantity = 0; |
| | | } |
| | | |
| | | return item; |
| | | }).ToList(); |
| | | |
| | | // 7. 计算仓库尺寸 |
| | | var maxRow = locations.Any() ? locations.Max(l => l.Row) : 0; |
| | | var maxColumn = locations.Any() ? locations.Max(l => l.Column) : 0; |
| | | var maxLayer = locations.Any() ? locations.Max(l => l.Layer) : 0; |
| | | |
| | | // 8. 构建返回结果 |
| | | return new Stock3DLayoutDTO |
| | | { |
| | | WarehouseId = warehouseId, |
| | | WarehouseName = warehouse?.WarehouseName ?? string.Empty, |
| | | MaxRow = maxRow, |
| | | MaxColumn = maxColumn, |
| | | MaxLayer = maxLayer, |
| | | MaterielCodeList = materielCodeList, |
| | | BatchNoList = batchNoList, |
| | | Locations = locationItems |
| | | }; |
| | | } |
| | | } |
| | | } |