using SqlSugar; using WIDESEA_Common.Constants; using WIDESEA_Common.StockEnum; using WIDESEA_Core; using WIDESEA_DTO.MES; using WIDESEA_DTO.Stock; using WIDESEA_IBasicService; using WIDESEA_IStockService; using WIDESEA_Model.Models; namespace WIDESEA_StockService { /// /// 库存服务聚合实现类 /// public class StockService : IStockService { /// /// 库存明细服务 /// public IStockInfoDetailService StockInfoDetailService { get; } /// /// 库存信息服务 /// public IStockInfoService StockInfoService { get; } /// /// 库存明细历史服务 /// public IStockInfoDetail_HtyService StockInfoDetail_HtyService { get; } /// /// 库存历史服务 /// public IStockInfo_HtyService StockInfo_HtyService { get; } /// /// 仓库服务 /// public IWarehouseService _warehouseService { get; } /// /// Mes接口服务 /// public IMesService _mesService { get; } /// /// 构造函数 /// /// 库存明细服务 /// 库存信息服务 /// 库存明细历史服务 /// 库存历史服务 public StockService( IStockInfoDetailService stockInfoDetailService, IStockInfoService stockInfoService, IStockInfoDetail_HtyService stockInfoDetail_HtyService, IStockInfo_HtyService stockInfo_HtyService, IMesService mesService, IWarehouseService warehouseService) { StockInfoDetailService = stockInfoDetailService; StockInfoService = stockInfoService; StockInfoDetail_HtyService = stockInfoDetail_HtyService; StockInfo_HtyService = stockInfo_HtyService; _mesService = mesService; _warehouseService = warehouseService; } /// /// 在事务中执行操作 /// private async Task ExecuteWithinTransactionAsync(Func> 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; } } /// /// 组盘 /// public async Task GroupPalletAsync(StockDTO stock) { WebResponseContent content = new WebResponseContent(); try { var now = DateTime.Now; var details = stock.Details.Select(item => new Dt_StockInfoDetail { MaterielCode = StockConstants.MATERIAL_CODE, MaterielName = StockConstants.MATERIAL_NAME, StockQuantity = item.Quantity, Unit = StockConstants.UNIT, Creater = StockConstants.SYSTEM_USER, OrderNo = StockConstants.DEFAULT_ORDER_NO, ProductionDate = now.ToString(), EffectiveDate = now.AddYears(1).ToString(), SerialNumber = item.CellBarcode, InboundOrderRowNo = item.Channel, Status = StockStatusEmun.组盘暂存.GetHashCode(), }).ToList(); var bindRequest = new BindContainerRequest { ContainerCode = stock?.TargetPalletNo, EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, ResourceCode = StockConstants.MES_RESOURCE_CODE, LocalTime = now, OperationType = StockConstants.MES_BIND_OPERATION_TYPE, ContainerSfcList = details.Select(d => new ContainerSfcItem { Sfc = d.SerialNumber, Location = d.InboundOrderRowNo.ToString(), }).ToList() }; return await ExecuteWithinTransactionAsync(async () => { 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 = stock.Roadway == "注液组盘机械手" ? (await _warehouseService.Db.Queryable().FirstAsync(w => w.WarehouseCode == "GW1")).WarehouseId : 0, StockStatus = StockStatusEmun.组盘暂存.GetHashCode(), Creater = StockConstants.SYSTEM_USER, Details = details }; result = StockInfoService.Repository.AddData(entity, x => x.Details); if (!result) return content.Error("组盘失败"); //var mesResult = _mesService.BindContainer(bindRequest); //if (mesResult == null || mesResult.Data == null || !mesResult.Data.IsSuccess) //{ // return content.Error($"组盘成功,但MES绑定失败: {mesResult?.Data?.Msg ?? mesResult?.ErrorMessage ?? "未知错误"}"); //} return content.OK("组盘成功"); }); } catch (Exception ex) { return content.Error($"组盘失败: {ex.Message}"); } } /// /// 换盘 /// public async Task ChangePalletAsync(StockDTO stock) { WebResponseContent content = new WebResponseContent(); try { if (stock == null || string.IsNullOrWhiteSpace(stock.TargetPalletNo) || string.IsNullOrWhiteSpace(stock.SourcePalletNo) || string.Equals(stock.SourcePalletNo, stock.TargetPalletNo, StringComparison.OrdinalIgnoreCase)) { return content.Error("源托盘号与目标托盘号相同"); } return await ExecuteWithinTransactionAsync(async () => { var sourceStock = await StockInfoService.Repository.QueryDataNavFirstAsync(s => s.PalletCode == stock.SourcePalletNo); if (sourceStock == null) return content.Error("源托盘不存在"); var targetStock = StockInfoService.Repository.QueryFirst(s => s.PalletCode == stock.TargetPalletNo); if (targetStock == null) { var newStock = new Dt_StockInfo { PalletCode = stock.TargetPalletNo, WarehouseId = sourceStock.WarehouseId, StockStatus = StockStatusEmun.组盘暂存.GetHashCode(), Creater = StockConstants.SYSTEM_USER, }; var newId = StockInfoService.Repository.AddData(newStock); if (newId <= 0) return content.Error("换盘失败"); targetStock = newStock; targetStock.Id = newId; } var serialNumbers = stock.Details.Select(d => d.Channel).Distinct().ToList(); if (!serialNumbers.Any()) return content.Error("未找到有效的序列号"); var detailEntities = StockInfoDetailService.Repository.QueryData( d => d.StockId == sourceStock.Id && serialNumbers.Contains(d.InboundOrderRowNo)); if (!detailEntities.Any()) return content.Error("未找到有效的库存明细"); if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "换盘")) <= 0) return content.Error("换盘历史记录保存失败"); if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock, targetStock }, "换盘")) <= 0) return content.Error("换盘历史记录保存失败"); // 调用MES解绑源托盘电芯 var unbindRequest = new UnBindContainerRequest { EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, ResourceCode = StockConstants.MES_RESOURCE_CODE, LocalTime = DateTime.Now, ContainCode = stock.SourcePalletNo, SfcList = detailEntities.Select(d => d.SerialNumber).ToList() }; var unbindResult = _mesService.UnBindContainer(unbindRequest); if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) { return content.Error($"换盘成功,但MES解绑失败: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "未知错误"}"); } detailEntities.ForEach(d => d.StockId = targetStock.Id); var result = await StockInfoDetailService.Repository.UpdateDataAsync(detailEntities); if (!result) return content.Error("换盘失败"); // 调用MES绑定目标托盘电芯 var bindRequest = new BindContainerRequest { ContainerCode = stock.TargetPalletNo, EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, ResourceCode = StockConstants.MES_RESOURCE_CODE, LocalTime = DateTime.Now, OperationType = StockConstants.MES_BIND_OPERATION_TYPE, ContainerSfcList = detailEntities.Select(d => new ContainerSfcItem { Sfc = d.SerialNumber, Location = d.InboundOrderRowNo.ToString() }).ToList() }; var bindResult = _mesService.BindContainer(bindRequest); if (bindResult == null || bindResult.Data == null || !bindResult.Data.IsSuccess) { return content.Error($"换盘成功,但MES绑定失败: {bindResult?.Data?.Msg ?? bindResult?.ErrorMessage ?? "未知错误"}"); } return content.OK("换盘成功"); }); } catch (Exception ex) { return content.Error($"换盘失败: {ex.Message}"); } } /// /// 拆盘 /// public async Task SplitPalletAsync(StockDTO stock) { WebResponseContent content = new WebResponseContent(); try { if (stock == null || string.IsNullOrWhiteSpace(stock.SourcePalletNo)) return content.Error("源托盘号不能为空"); return await ExecuteWithinTransactionAsync(async () => { 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()) { 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 content.Error("未找到有效的库存明细"); if (await StockInfoDetail_HtyService.Repository.AddDataAsync(CreateDetailHistory(detailEntities, "拆盘")) <= 0) return content.Error("拆盘历史记录保存失败"); if (await StockInfo_HtyService.Repository.AddDataAsync(CreateStockHistory(new[] { sourceStock }, "拆盘")) <= 0) return content.Error("拆盘历史记录保存失败"); // 调用MES解绑电芯 var unbindRequest = new UnBindContainerRequest { EquipmentCode = StockConstants.MES_EQUIPMENT_CODE, ResourceCode = StockConstants.MES_RESOURCE_CODE, LocalTime = DateTime.Now, ContainCode = stock.SourcePalletNo, SfcList = detailEntities.Select(d => d.SerialNumber).ToList() }; var unbindResult = _mesService.UnBindContainer(unbindRequest); if (unbindResult == null || unbindResult.Data == null || !unbindResult.Data.IsSuccess) { return content.Error($"拆盘成功,但MES解绑失败: {unbindResult?.Data?.Msg ?? unbindResult?.ErrorMessage ?? "未知错误"}"); } var result = await StockInfoDetailService.Repository.DeleteDataAsync(detailEntities); if (!result) return content.Error("拆盘失败"); return content.OK("拆盘成功"); }); } catch (Exception ex) { return content.Error($"拆盘失败: {ex.Message}"); } } /// /// 堆垛机换盘后更新库存信息(清空库位信息) /// /// /// public async Task 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 CreateDetailHistory(IEnumerable details, string operateType) { var now = DateTime.Now; return details.Select(d => new Dt_StockInfoDetail_Hty { SourceId = d.Id, OperateType = operateType, InsertTime = now, 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 static List CreateStockHistory(IEnumerable stocks, string operateType) { var now = DateTime.Now; return stocks.Select(s => new Dt_StockInfo_Hty { SourceId = s.Id, OperateType = operateType, InsertTime = now, 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(); } } }