| | |
| | | using WIDESEA_Common.StockEnum; |
| | | using SqlSugar; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Stock; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_Model.Models; |
| | |
| | | namespace WIDESEA_StockService |
| | | { |
| | | /// <summary> |
| | | /// 库存服务 |
| | | /// 库存服务聚合实现类 |
| | | /// </summary> |
| | | public class StockSerivce : IStockService |
| | | public class StockService : IStockService |
| | | { |
| | | /// <summary> |
| | | /// 库存明细服务 |
| | | /// </summary> |
| | | public IStockInfoDetailService StockInfoDetailService { get; } |
| | | |
| | | /// <summary> |
| | | /// 库存信息服务 |
| | | /// </summary> |
| | | public IStockInfoService StockInfoService { get; } |
| | | |
| | | /// <summary> |
| | | /// 库存明细历史服务 |
| | | /// </summary> |
| | | public IStockInfoDetail_HtyService StockInfoDetail_HtyService { get; } |
| | | |
| | | /// <summary> |
| | | /// 库存历史服务 |
| | | /// </summary> |
| | | public IStockInfo_HtyService StockInfo_HtyService { get; } |
| | | |
| | | /// <summary> |
| | | /// 构造函数 |
| | | /// </summary> |
| | | /// <param name="stockInfoDetailService">库存明细服务</param> |
| | | /// <param name="stockInfoService">库存服务</param> |
| | | /// <param name="stockInfoService">库存信息服务</param> |
| | | /// <param name="stockInfoDetail_HtyService">库存明细历史服务</param> |
| | | /// <param name="stockInfo_HtyService">库存历史服务</param> |
| | | public StockSerivce(IStockInfoDetailService stockInfoDetailService, IStockInfoService stockInfoService, IStockInfoDetail_HtyService stockInfoDetail_HtyService, IStockInfo_HtyService stockInfo_HtyService) |
| | | public StockService( |
| | | IStockInfoDetailService stockInfoDetailService, |
| | | IStockInfoService stockInfoService, |
| | | IStockInfoDetail_HtyService stockInfoDetail_HtyService, |
| | | IStockInfo_HtyService stockInfo_HtyService) |
| | | { |
| | | StockInfoDetailService = stockInfoDetailService; |
| | | StockInfoService = stockInfoService; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 在事务中执行操作 |
| | | /// </summary> |
| | | private async Task<WebResponseContent> ExecuteWithinTransactionAsync(Func<Task<WebResponseContent>> operation) |
| | | { |
| | | var db = StockInfoService.Repository.Db as SqlSugarClient; |
| | | if (db == null) |
| | | { |
| | | return WebResponseContent.Instance.Error("Database context does not support transactions"); |
| | | } |
| | | |
| | | var ownsTransaction = db.Ado.Transaction == null; |
| | | try |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.BeginTran(); |
| | | } |
| | | |
| | | var result = await operation(); |
| | | if (result?.Status == true) |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.CommitTran(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | return result ?? WebResponseContent.Instance.Error("Transaction failed"); |
| | | } |
| | | catch |
| | | { |
| | | if (ownsTransaction) |
| | | { |
| | | db.RollbackTran(); |
| | | } |
| | | throw; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 组盘 |
| | | /// </summary> |
| | | /// <param name="stock">组盘数据</param> |
| | | /// <returns>是否成功</returns> |
| | | public async Task<bool> GroupPallet(StockDTO stock) |
| | | public async Task<WebResponseContent> GroupPalletAsync(StockDTO stock) |
| | | { |
| | | // 组装明细数据 |
| | | WebResponseContent content = new WebResponseContent(); |
| | | var now = DateTime.Now; |
| | | var details = stock.Details.Select(item => new Dt_StockInfoDetail() |
| | | var details = stock.Details.Select(item => new Dt_StockInfoDetail |
| | | { |
| | | MaterielCode = "电芯", |
| | | MaterielName = "电芯", |
| | | StockQuantity = item.Quantity, |
| | | Unit = "PCS", |
| | | Creater = "system", |
| | |
| | | EffectiveDate = now.AddYears(1).ToString(), |
| | | SerialNumber = item.CellBarcode, |
| | | InboundOrderRowNo = item.Channel, |
| | | MaterielName = "电芯", |
| | | Status = StockStatusEmun.组盘暂存.GetHashCode(), |
| | | }).ToList(); |
| | | |
| | | // 如果托盘已存在,直接新增明细 |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | if (existingStock != null) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | details.ForEach(detail => detail.StockId = existingStock.Id); |
| | | return await StockInfoDetailService.Repository.AddDataAsync(details) > 0; |
| | | } |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | var result = false; |
| | | if (existingStock != null) |
| | | { |
| | | details.ForEach(d => d.StockId = existingStock.Id); |
| | | result = await StockInfoDetailService.Repository.AddDataAsync(details) > 0; |
| | | return result ? content.OK("组盘成功") : content.Error("组盘失败"); |
| | | } |
| | | |
| | | // 托盘不存在则创建并写入明细 |
| | | var entity = new Dt_StockInfo() |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = 1, |
| | | StockStatus = 1, |
| | | Creater = "system", |
| | | Details = details |
| | | }; |
| | | var entity = new Dt_StockInfo |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = 1, |
| | | StockStatus = 1, |
| | | Creater = "system", |
| | | Details = details |
| | | }; |
| | | |
| | | //Dt_Task dt_Task = new Dt_Task() |
| | | //{ |
| | | // TaskNum = 0, |
| | | // PalletCode = stock.PalletNo, |
| | | // PalletType = 1, |
| | | // Roadway = "1", |
| | | // TaskType = TaskTypeEnum.Inbound.GetHashCode(), |
| | | // TaskStatus = TaskStatusEnum.New.GetHashCode(), |
| | | // SourceAddress = stock.LineNo, |
| | | // TargetAddress = "组盘区", |
| | | // CurrentAddress = stock.LineNo, |
| | | // NextAddress = "组盘区", |
| | | // WarehouseId = 1, |
| | | // Grade = 1, |
| | | // Creater = "system", |
| | | //}; |
| | | |
| | | return StockInfoService.Repository.AddData(entity, x => x.Details); |
| | | result = StockInfoService.Repository.AddData(entity, x => x.Details); |
| | | return result ? content.OK("组盘成功") : content.Error("组盘失败"); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 换盘 |
| | | /// </summary> |
| | | /// <param name="stock">需要换盘的明细数据</param> |
| | | /// <returns>是否成功</returns> |
| | | public async Task<bool> ChangePallet(StockDTO stock) |
| | | public async Task<WebResponseContent> ChangePalletAsync(StockDTO stock) |
| | | { |
| | | // 参数校验 |
| | | if (stock == null || string.IsNullOrWhiteSpace(stock.TargetPalletNo) || string.IsNullOrWhiteSpace(stock.SourcePalletNo)) |
| | | WebResponseContent content = new WebResponseContent(); |
| | | if (stock == null || |
| | | string.IsNullOrWhiteSpace(stock.TargetPalletNo) || |
| | | string.IsNullOrWhiteSpace(stock.SourcePalletNo) || |
| | | string.Equals(stock.SourcePalletNo, stock.TargetPalletNo, StringComparison.OrdinalIgnoreCase)) |
| | | { |
| | | return false; |
| | | return content.Error("源托盘号与目标托盘号相同"); |
| | | } |
| | | |
| | | // 新旧托盘一致不处理 |
| | | if (string.Equals(stock.SourcePalletNo, stock.TargetPalletNo, StringComparison.OrdinalIgnoreCase)) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | return false; |
| | | } |
| | | var sourceStock = await StockInfoService.Repository.QueryDataNavFirstAsync(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("源托盘不存在"); |
| | | |
| | | // 查询源托盘 |
| | | var sourceStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // 查询或创建目标托盘 |
| | | var targetStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | if (targetStock == null) |
| | | { |
| | | var newStock = new Dt_StockInfo() |
| | | var targetStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); |
| | | if (targetStock == null) |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = sourceStock.WarehouseId, |
| | | StockStatus = sourceStock.StockStatus, |
| | | Creater = "system" |
| | | }; |
| | | var newStock = new Dt_StockInfo |
| | | { |
| | | PalletCode = stock.TargetPalletNo, |
| | | WarehouseId = sourceStock.WarehouseId, |
| | | StockStatus = StockStatusEmun.组盘暂存.GetHashCode(), |
| | | Creater = "system", |
| | | }; |
| | | |
| | | var newId = StockInfoService.Repository.AddData(newStock); |
| | | if (newId <= 0) |
| | | { |
| | | return false; |
| | | var newId = StockInfoService.Repository.AddData(newStock); |
| | | if (newId <= 0) return content.Error("换盘失败"); |
| | | |
| | | targetStock = newStock; |
| | | targetStock.Id = newId; |
| | | } |
| | | |
| | | targetStock = newStock; |
| | | targetStock.Id = newId; |
| | | } |
| | | var serialNumbers = stock.Details.Select(d => d.Channel).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) return content.Error("未找到有效的序列号"); |
| | | |
| | | // 获取需要转移的条码 |
| | | var serialNumbers = stock.Details.Select(d => d.CellBarcode).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) |
| | | { |
| | | return false; |
| | | } |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.InboundOrderRowNo)); |
| | | if (!detailEntities.Any()) return content.Error("未找到有效的库存明细"); |
| | | |
| | | // 查询源托盘对应的明细 |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.SerialNumber)); |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "换盘")) <= 0) |
| | | return content.Error("换盘历史记录保存失败"); |
| | | |
| | | if (!detailEntities.Any()) |
| | | { |
| | | return false; |
| | | } |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock, targetStock }, "换盘")) <= 0) |
| | | return content.Error("换盘历史记录保存失败"); |
| | | |
| | | // 写入历史记录 |
| | | var detailHistory = CreateDetailHistory(detailEntities, "换盘"); |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(detailHistory) <= 0) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | var stockHistory = CreateStockHistory(new List<Dt_StockInfo> { sourceStock, targetStock }, "换盘"); |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(stockHistory) <= 0) |
| | | { |
| | | return false; |
| | | } |
| | | |
| | | // 更新明细的托盘主键 |
| | | detailEntities.ForEach(detail => detail.StockId = targetStock.Id); |
| | | return await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | detailEntities.ForEach(d => d.StockId = targetStock.Id); |
| | | var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); |
| | | if (!result) return content.Error("换盘失败"); |
| | | return content.OK("换盘成功"); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 拆盘 |
| | | /// </summary> |
| | | /// <param name="stock">需要拆盘的明细数据</param> |
| | | /// <returns>是否成功</returns> |
| | | public async Task<bool> SplitPallet(StockDTO stock) |
| | | public async Task<WebResponseContent> SplitPalletAsync(StockDTO stock) |
| | | { |
| | | // 参数校验 |
| | | WebResponseContent content = new WebResponseContent(); |
| | | if (stock == null || string.IsNullOrWhiteSpace(stock.SourcePalletNo)) |
| | | { |
| | | return false; |
| | | } |
| | | return content.Error("源托盘号不能为空"); |
| | | |
| | | // 查询源托盘 |
| | | var sourceStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) |
| | | return await ExecuteWithinTransactionAsync(async () => |
| | | { |
| | | return false; |
| | | } |
| | | var sourceStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.SourcePalletNo); |
| | | if (sourceStock == null) return content.Error("源托盘不存在"); |
| | | |
| | | // 获取需要拆除的条码 |
| | | var serialNumbers = stock.Details.Select(d => d.CellBarcode).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) |
| | | { |
| | | return false; |
| | | } |
| | | var serialNumbers = stock.Details.Select(d => d.CellBarcode).Distinct().ToList(); |
| | | if (!serialNumbers.Any()) |
| | | { |
| | | serialNumbers = sourceStock.Details |
| | | .Where(x => stock.Details.Any(d => d.Channel == x.InboundOrderRowNo)) |
| | | .Select(x => x.SerialNumber) |
| | | .ToList(); |
| | | } |
| | | |
| | | // 查询源托盘对应的明细 |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData(d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.SerialNumber)); |
| | | if (!detailEntities.Any()) |
| | | { |
| | | return false; |
| | | } |
| | | var detailEntities = StockInfoDetailService.Repository.QueryData( |
| | | d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.SerialNumber)); |
| | | if (!detailEntities.Any()) return content.Error("未找到有效的库存明细"); |
| | | |
| | | // 写入历史记录 |
| | | var detailHistory = CreateDetailHistory(detailEntities, "拆盘"); |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(detailHistory) <= 0) |
| | | { |
| | | return false; |
| | | } |
| | | if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "拆盘")) <= 0) |
| | | return content.Error("拆盘历史记录保存失败"); |
| | | |
| | | var stockHistory = CreateStockHistory(new List<Dt_StockInfo> { sourceStock }, "拆盘"); |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(stockHistory) <= 0) |
| | | { |
| | | return false; |
| | | } |
| | | if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "拆盘")) <= 0) |
| | | return content.Error("拆盘历史记录保存失败"); |
| | | |
| | | // 删除明细 |
| | | return await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); |
| | | var result = await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); |
| | | if (!result) return content.Error("拆盘失败"); |
| | | return content.OK("拆盘成功"); |
| | | }); |
| | | } |
| | | |
| | | private List<Dt_StockInfoDetail_Hty> CreateDetailHistory(IEnumerable<Dt_StockInfoDetail> details, string operateType) |
| | | /// <summary> |
| | | /// 堆垛机换盘后更新库存信息(清空库位信息) |
| | | /// </summary> |
| | | /// <param name="stock"></param> |
| | | /// <returns></returns> |
| | | public async Task<WebResponseContent> UpdateStockInfoAsync(StockInfoDTO stock) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | if (string.IsNullOrWhiteSpace(stock.PalletCode)) return content.Error("托盘号不能为空"); |
| | | |
| | | var existingStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.PalletCode); |
| | | if (existingStock == null) return content.Error("托盘信息不存在"); |
| | | |
| | | existingStock.LocationCode = ""; |
| | | existingStock.LocationId = 0; |
| | | |
| | | var result = await StockInfoService.Repository.UpdateDataAsync(existingStock); |
| | | if (!result) return content.Error("更新库存信息失败"); |
| | | return content.OK("更新库存信息成功"); |
| | | } |
| | | |
| | | private static List<Dt_StockInfoDetail_Hty> CreateDetailHistory(IEnumerable<Dt_StockInfoDetail> details, string operateType) |
| | | { |
| | | var now = DateTime.Now; |
| | | return details.Select(detail => new Dt_StockInfoDetail_Hty |
| | | return details.Select(d => new Dt_StockInfoDetail_Hty |
| | | { |
| | | SourceId = detail.Id, |
| | | SourceId = d.Id, |
| | | OperateType = operateType, |
| | | InsertTime = now, |
| | | StockId = detail.StockId, |
| | | MaterielCode = detail.MaterielCode, |
| | | MaterielName = detail.MaterielName, |
| | | OrderNo = detail.OrderNo, |
| | | BatchNo = detail.BatchNo, |
| | | ProductionDate = detail.ProductionDate, |
| | | EffectiveDate = detail.EffectiveDate, |
| | | SerialNumber = detail.SerialNumber, |
| | | StockQuantity = detail.StockQuantity, |
| | | OutboundQuantity = detail.OutboundQuantity, |
| | | Status = detail.Status, |
| | | Unit = detail.Unit, |
| | | InboundOrderRowNo = detail.InboundOrderRowNo, |
| | | Remark = detail.Remark, |
| | | Creater = detail.Creater, |
| | | CreateDate = detail.CreateDate, |
| | | Modifier = detail.Modifier, |
| | | ModifyDate = detail.ModifyDate |
| | | StockId = d.StockId, |
| | | MaterielCode = d.MaterielCode, |
| | | MaterielName = d.MaterielName, |
| | | OrderNo = d.OrderNo, |
| | | BatchNo = d.BatchNo, |
| | | ProductionDate = d.ProductionDate, |
| | | EffectiveDate = d.EffectiveDate, |
| | | SerialNumber = d.SerialNumber, |
| | | StockQuantity = d.StockQuantity, |
| | | OutboundQuantity = d.OutboundQuantity, |
| | | Status = d.Status, |
| | | Unit = d.Unit, |
| | | InboundOrderRowNo = d.InboundOrderRowNo, |
| | | Remark = d.Remark, |
| | | Creater = d.Creater, |
| | | CreateDate = d.CreateDate, |
| | | Modifier = d.Modifier, |
| | | ModifyDate = d.ModifyDate |
| | | }).ToList(); |
| | | } |
| | | |
| | | private List<Dt_StockInfo_Hty> CreateStockHistory(IEnumerable<Dt_StockInfo> stocks, string operateType) |
| | | private static List<Dt_StockInfo_Hty> CreateStockHistory(IEnumerable<Dt_StockInfo> stocks, string operateType) |
| | | { |
| | | var now = DateTime.Now; |
| | | return stocks.Select(stock => new Dt_StockInfo_Hty |
| | | return stocks.Select(s => new Dt_StockInfo_Hty |
| | | { |
| | | SourceId = stock.Id, |
| | | SourceId = s.Id, |
| | | OperateType = operateType, |
| | | InsertTime = now, |
| | | PalletCode = stock.PalletCode, |
| | | PalletType = stock.PalletType, |
| | | LocationCode = stock.LocationCode, |
| | | WarehouseId = stock.WarehouseId, |
| | | StockStatus = stock.StockStatus, |
| | | Remark = stock.Remark, |
| | | Creater = stock.Creater, |
| | | CreateDate = stock.CreateDate, |
| | | Modifier = stock.Modifier, |
| | | ModifyDate = stock.ModifyDate |
| | | PalletCode = s.PalletCode, |
| | | PalletType = s.PalletType, |
| | | LocationCode = s.LocationCode, |
| | | WarehouseId = s.WarehouseId, |
| | | StockStatus = s.StockStatus, |
| | | Remark = s.Remark, |
| | | Creater = s.Creater, |
| | | CreateDate = s.CreateDate, |
| | | Modifier = s.Modifier, |
| | | ModifyDate = s.ModifyDate, |
| | | LocationId = s.LocationId, |
| | | OutboundDate = s.OutboundDate |
| | | }).ToList(); |
| | | } |
| | | } |