diff --git a/DOAN.Admin.WebApi/Controllers/MES/Product/ProWorkorderController.cs b/DOAN.Admin.WebApi/Controllers/MES/Product/ProWorkorderController.cs index 395602c..d5baad4 100644 --- a/DOAN.Admin.WebApi/Controllers/MES/Product/ProWorkorderController.cs +++ b/DOAN.Admin.WebApi/Controllers/MES/Product/ProWorkorderController.cs @@ -400,7 +400,7 @@ namespace DOAN.Admin.WebApi.Controllers } catch (Exception ex) { - return ToResponse(500, ex.Message); + return ToResponse(new ApiResult(500, ex.Message)); } } @@ -421,7 +421,7 @@ namespace DOAN.Admin.WebApi.Controllers catch (Exception ex) { - return ToResponse(500, ex.Message); + return ToResponse(new ApiResult(500, ex.Message)); } } @@ -447,7 +447,7 @@ namespace DOAN.Admin.WebApi.Controllers } catch (Exception ex) { - return ToResponse(500, ex.Message); + return ToResponse(new ApiResult(500, ex.Message)); } } @@ -472,7 +472,7 @@ namespace DOAN.Admin.WebApi.Controllers } catch (Exception ex) { - return ToResponse(500, ex.Message); + return ToResponse(new ApiResult(500, ex.Message)); } } @@ -497,7 +497,185 @@ namespace DOAN.Admin.WebApi.Controllers } catch (Exception ex) { - return ToResponse(500, ex.Message); + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 根据工单号查询物料库存 + /// + /// 工单号 + /// 物料库存信息列表 + [HttpGet("GetMaterialInventoryList/{workorder}")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:query")] + public IActionResult GetMaterialInventoryList(string workorder) + { + try + { + if (string.IsNullOrEmpty(workorder)) + { + return ToResponse(ApiResult.Error($"工单号不能为空")); + } + + var response = _ProWorkorderMaterialService.GetMaterialInventoryList(workorder); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 领料接口 + /// + /// 领料请求参数 + /// 操作结果 + [HttpPost("TakeMaterial")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:edit")] + [Log(Title = "领料操作", BusinessType = BusinessType.UPDATE)] + public IActionResult TakeMaterial([FromBody] MaterialTakeRequestDto request) + { + try + { + if (request == null) + { + return ToResponse(ApiResult.Error($"领料请求参数不能为空")); + } + + var response = _ProWorkorderMaterialService.TakeMaterial(request); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 成品入库接口 + /// + /// 成品入库请求参数 + /// 操作结果 + [HttpPost("StoreProduct")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:edit")] + [Log(Title = "成品入库操作", BusinessType = BusinessType.UPDATE)] + public IActionResult StoreProduct([FromBody] ProductStorageRequestDto request) + { + try + { + if (request == null) + { + return ToResponse(ApiResult.Error($"成品入库请求参数不能为空")); + } + + var response = _ProWorkorderMaterialService.StoreProduct(request); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 出货接口 + /// + /// 出货请求参数 + /// 操作结果 + [HttpPost("ShipProduct")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:edit")] + [Log(Title = "出货操作", BusinessType = BusinessType.UPDATE)] + public IActionResult ShipProduct([FromBody] ShipmentRequestDto request) + { + try + { + if (request == null) + { + return ToResponse(ApiResult.Error($"出货请求参数不能为空")); + } + + var response = _ProWorkorderMaterialService.ShipProduct(request); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 根据工单号获取可领料工单清单 + /// + /// 工单号 + /// 可领料工单清单 + [HttpGet("GetPickableWorkordersByWorkorder/{workorder}")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:query")] + public IActionResult GetPickableWorkordersByWorkorder(string workorder) + { + try + { + if (string.IsNullOrEmpty(workorder)) + { + return ToResponse(ApiResult.Error($"工单号不能为空")); + } + + var response = _ProWorkorderMaterialService.GetPickableWorkordersByWorkorder(workorder); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 根据工单号获取可出货订单清单 + /// + /// 工单号 + /// 可出货订单清单 + [HttpGet("GetShippableOrdersByWorkorder/{workorder}")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:query")] + public IActionResult GetShippableOrdersByWorkorder(string workorder) + { + try + { + if (string.IsNullOrEmpty(workorder)) + { + return ToResponse(ApiResult.Error($"工单号不能为空")); + } + + var response = _ProWorkorderMaterialService.GetShippableOrdersByWorkorder(workorder); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); + } + } + + /// + /// 根据工单号查询成品库存 + /// + /// 工单号 + /// 成品库存信息列表 + [HttpGet("GetProductInventoryList/{workorder}")] + [ActionPermissionFilter(Permission = "productManagement:proworkorder:query")] + public IActionResult GetProductInventoryList(string workorder) + { + try + { + if (string.IsNullOrEmpty(workorder)) + { + return ToResponse(ApiResult.Error($"工单号不能为空")); + } + + var response = _ProWorkorderMaterialService.GetProductInventoryList(workorder); + return SUCCESS(response); + } + catch (Exception ex) + { + return ToResponse(new ApiResult(500, ex.Message)); } } } diff --git a/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs b/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs index 534e4e5..6dd6782 100644 --- a/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs +++ b/DOAN.Model/MES/Material/Dto/MmRecordOutboundDto.cs @@ -1,4 +1,3 @@ - namespace DOAN.Model.BZFM.Dto { /// @@ -89,10 +88,17 @@ namespace DOAN.Model.BZFM.Dto public string OutboundNo { get; set; } [Required(ErrorMessage = "物料编码不能为空")] + + // 库存Id + public int InventoryId { get; set; } = -1; + public string MaterialCode { get; set; } public string MaterialName { get; set; } + public string SupplierName { get; set; } + public string SupplierCode { get; set; } + [Required(ErrorMessage = "仓库编码不能为空")] public string WarehouseCode { get; set; } @@ -119,11 +125,12 @@ namespace DOAN.Model.BZFM.Dto public string Remarks { get; set; } public DateTime? CreatedTime { get; set; } + [ExcelColumn(Name = "出库类型")] public string TransactionTypeLabel { get; set; } /// - /// 工单号(一旦确定,不可更改) + /// 工单号(一旦确定,不可更改) /// public string Workorder { get; set; } @@ -206,4 +213,4 @@ namespace DOAN.Model.BZFM.Dto [SugarColumn(ColumnName = "workorder_raw")] public string WorkorderRaw { get; set; } } -} \ No newline at end of file +} diff --git a/DOAN.Model/MES/Material/MmMaterial.cs b/DOAN.Model/MES/Material/MmMaterial.cs index 177fb90..ad06628 100644 --- a/DOAN.Model/MES/Material/MmMaterial.cs +++ b/DOAN.Model/MES/Material/MmMaterial.cs @@ -90,8 +90,14 @@ namespace DOAN.Model.BZFM public DateTime? UpdatedTime { get; set; } /// - /// 描述 + /// 描述 /// public string Description { get; set; } + + /// + /// 父物料编码 + /// + [SugarColumn(ColumnName = "parent_material_code")] + public string ParentMaterialCode { get; set; } } } \ No newline at end of file diff --git a/DOAN.Model/MES/Material/MmRecordOutbound.cs b/DOAN.Model/MES/Material/MmRecordOutbound.cs index e493def..7ad371c 100644 --- a/DOAN.Model/MES/Material/MmRecordOutbound.cs +++ b/DOAN.Model/MES/Material/MmRecordOutbound.cs @@ -31,6 +31,18 @@ namespace DOAN.Model.BZFM [SugarColumn(ColumnName = "material_name")] public string MaterialName { get; set; } + /// + /// 物料编码 + /// + [SugarColumn(ColumnName = "supplier_code")] + public string SupplierCode { get; set; } + + /// + /// 物料名称 + /// + [SugarColumn(ColumnName = "supplier_name")] + public string SupplierName { get; set; } + /// /// 仓库编码 /// diff --git a/DOAN.Model/MES/Product/Dto/WorkorderMaterialDto.cs b/DOAN.Model/MES/Product/Dto/WorkorderMaterialDto.cs index 2758fc4..2f63f38 100644 --- a/DOAN.Model/MES/Product/Dto/WorkorderMaterialDto.cs +++ b/DOAN.Model/MES/Product/Dto/WorkorderMaterialDto.cs @@ -7,6 +7,10 @@ namespace DOAN.Model.MES.product.Dto /// public class MaterialTakeDto { + /// + /// 主键 + /// + public int Id { get; set; } /// /// 物料编码 /// @@ -17,6 +21,16 @@ namespace DOAN.Model.MES.product.Dto /// public string MaterialName { get; set; } + /// + /// 供应商编码 + /// + public string SupplierCode { get; set; } + + /// + /// 供应商名称 + /// + public string SupplierName { get; set; } + /// /// 批次号 /// @@ -63,6 +77,10 @@ namespace DOAN.Model.MES.product.Dto /// public class ProductStorageDto { + /// + /// 主键 + /// + public int Id { get; set; } /// /// 物料编码 /// @@ -125,6 +143,10 @@ namespace DOAN.Model.MES.product.Dto /// public class ShipmentDto { + /// + /// 主键 + /// + public int Id { get; set; } /// /// 物料编码 /// @@ -180,4 +202,134 @@ namespace DOAN.Model.MES.product.Dto /// public string WorkorderRaw { get; set; } } + + /// + /// 物料库存信息数据传输对象 + /// + public class MaterialInventoryDto + { + /// + /// 物料ID + /// + public int MaterialId { get; set; } + + /// + /// 物料名称 + /// + public string MaterialName { get; set; } + /// + /// 物料编码 + /// + public string MaterialCode { get; set; } + + /// + /// 当前库存数量 + /// + public decimal CurrentQuantity { get; set; } + + /// + /// 供应商编码 + /// + public string SupplierCode { get; set; } + + /// + /// 供应商名称 + /// + public string SupplierName { get; set; } + + + /// + /// 单位 + /// + public string Unit { get; set; } + + /// + /// 批次号 + /// + public string BatchNo { get; set; } + } + + /// + /// 领料请求数据传输对象 + /// + public class MaterialTakeRequestDto + { + /// + /// 工单号 + /// + public string Workorder { get; set; } + + /// + /// 原材料对应工单号 + /// + public string WorkorderRaw { get; set; } + + /// + /// 领料数量 + /// + public decimal Quantity { get; set; } + + /// + /// 物料库存ID + /// + public int MaterialInventoryId { get; set; } + + /// + /// 炉号(可选) + /// + public string StoveCode { get; set; } + + /// + /// 操作人 + /// + public string Operator { get; set; } + } + + /// + /// 成品入库请求数据传输对象 + /// + public class ProductStorageRequestDto + { + /// + /// 工单号 + /// + public string Workorder { get; set; } + + /// + /// 成品数量 + /// + public decimal Quantity { get; set; } + + /// + /// 操作人 + /// + public string Operator { get; set; } + } + + /// + /// 出货请求数据传输对象 + /// + public class ShipmentRequestDto + { + /// + /// 工单号 + /// + public string Workorder { get; set; } + + /// + /// 出货数量 + /// + public decimal Quantity { get; set; } + + /// + /// 订单ID + /// + public string OrderId { get; set; } + + + /// + /// 操作人 + /// + public string Operator { get; set; } + } } diff --git a/DOAN.Service/MES/Material/MmInventoryService.cs b/DOAN.Service/MES/Material/MmInventoryService.cs index 8ef0dd5..899c544 100644 --- a/DOAN.Service/MES/Material/MmInventoryService.cs +++ b/DOAN.Service/MES/Material/MmInventoryService.cs @@ -301,41 +301,83 @@ namespace DOAN.Service.BZFM // 计算有符号变动量(蓝单为正,红单为负) decimal delta = GetSignedQuantity(parm.ReceiptType, parm.Quantity); - var mmMaterial = Context - .Queryable() - .Where(it => it.MaterialCode == parm.MaterialCode) - .First(); - if (mmMaterial == null) - return "物料不存在!"; - - var mmLocation = Context - .Queryable() - .Where(it => it.WarehouseCode == parm.WarehouseCode) - .Where(it => it.LocationCode == parm.LocationCode) - .First(); - if (mmLocation == null) - return "仓库编码或库位编码不存在!"; - Context.Ado.BeginTran(); - - var mmInventory = Context - .Queryable() - .Where(it => it.MaterialCode == parm.MaterialCode) - .Where(it => it.BatchNo == parm.BatchNo) - .Where(it => it.WarehouseCode == parm.WarehouseCode) - .Where(it => it.LocationCode == parm.LocationCode) - .First(); - - if (mmInventory == null) + MmInventory mmInventory = null; + if (parm.InventoryId == -1) { - if (parm.ReceiptType == 1) + var mmMaterial = Context + .Queryable() + .Where(it => it.MaterialCode == parm.MaterialCode) + .WhereIF( + !string.IsNullOrEmpty(parm.SupplierCode), + it => it.SupplierCode == parm.SupplierCode + ) + .First(); + if (mmMaterial == null) + return "物料不存在!"; + + var mmLocation = Context + .Queryable() + .Where(it => it.WarehouseCode == parm.WarehouseCode) + .Where(it => it.LocationCode == parm.LocationCode) + .First(); + if (mmLocation == null) + return "仓库编码或库位编码不存在!"; + mmInventory = Context + .Queryable() + .Where(it => it.MaterialCode == parm.MaterialCode) + .Where(it => it.BatchNo == parm.BatchNo) + .Where(it => it.WarehouseCode == parm.WarehouseCode) + .Where(it => it.LocationCode == parm.LocationCode) + .First(); + if (mmInventory == null) { - //库存为0或者不存在,不允许出库 - Context.Ado.RollbackTran(); - return "库存不存在,禁止出库!"; + if (parm.ReceiptType == 1) + { + //库存为0或者不存在,不允许出库 + Context.Ado.RollbackTran(); + return "库存不存在,禁止出库!"; + } + var newInventory = new MmInventory() + { + MaterialCode = mmMaterial.MaterialCode, + MaterialName = mmMaterial.MaterialName, + SupplierCode = mmMaterial.SupplierCode, + SupplierName = mmMaterial.SupplierName, + LocationCode = mmLocation.LocationCode, + LocationName = mmLocation.LocationName, + WarehouseCode = mmLocation.WarehouseCode, + WarehouseName = mmLocation.WarehouseName, + + BatchNo = parm.BatchNo, + CurrentQty = -delta, + Unit = parm.Unit, + LastUpdatedTime = null, + CreatedTime = nowDate, + }; + Context.Insertable(newInventory).ExecuteCommand(); + mmInventory = newInventory; } - var newInventory = new MmInventory() + else { + if (mmInventory.CurrentQty - delta < 0) + { + Context.Ado.RollbackTran(); + return "库存不足,无法出库!"; + } + mmInventory.CurrentQty -= delta; + Context + .Updateable(mmInventory) + .UpdateColumns(it => it.CurrentQty) + .ExecuteCommand(); + } + + var outboundNo = GenerateReceiptNo("CK"); + MmRecordOutbound newRecord = new() + { + OutboundNo = outboundNo, + BatchNo = parm.BatchNo, + Operator = parm.Operator, MaterialCode = mmMaterial.MaterialCode, MaterialName = mmMaterial.MaterialName, SupplierCode = mmMaterial.SupplierCode, @@ -345,54 +387,100 @@ namespace DOAN.Service.BZFM WarehouseCode = mmLocation.WarehouseCode, WarehouseName = mmLocation.WarehouseName, - BatchNo = parm.BatchNo, - CurrentQty = -delta, + //TODO 待调整(可能涉及记录汇总) + Quantity = -delta, Unit = parm.Unit, - LastUpdatedTime = null, CreatedTime = nowDate, + TransactionType = parm.TransactionType, + Workorder = parm.Workorder, + WorkorderRaw = parm.WorkorderRaw, + OrderNo = parm.OrderNo, + Remarks = parm.Remarks, }; - Context.Insertable(newInventory).ExecuteCommand(); + Context.Insertable(newRecord).ExecuteCommand(); + Context.Ado.CommitTran(); + return "ok"; + } else { - if (mmInventory.CurrentQty - delta < 0) + mmInventory = Context + .Queryable() + .Where(it => it.Id == parm.InventoryId) + .First(); + if (mmInventory == null) { - Context.Ado.RollbackTran(); - return "库存不足,无法出库!"; + if (parm.ReceiptType == 1) + { + //库存为0或者不存在,不允许出库 + Context.Ado.RollbackTran(); + return "库存不存在,禁止出库!"; + } + var newInventory = new MmInventory() + { + MaterialCode = mmInventory.MaterialCode, + MaterialName = mmInventory.MaterialName, + SupplierCode = mmInventory.SupplierCode, + SupplierName = mmInventory.SupplierName, + LocationCode = mmInventory.LocationCode, + LocationName = mmInventory.LocationName, + WarehouseCode = mmInventory.WarehouseCode, + WarehouseName = mmInventory.WarehouseName, + BatchNo = parm.BatchNo, + CurrentQty = -delta, + Unit = parm.Unit, + LastUpdatedTime = null, + CreatedTime = nowDate, + }; + Context.Insertable(newInventory).ExecuteCommand(); + mmInventory = newInventory; } - mmInventory.CurrentQty -= delta; - Context - .Updateable(mmInventory) - .UpdateColumns(it => it.CurrentQty) - .ExecuteCommand(); + else + { + if (mmInventory.CurrentQty - delta < 0) + { + Context.Ado.RollbackTran(); + return "库存不足,无法出库!"; + } + mmInventory.CurrentQty -= delta; + Context + .Updateable(mmInventory) + .UpdateColumns(it => it.CurrentQty) + .ExecuteCommand(); + } + + var outboundNo = GenerateReceiptNo("CK"); + MmRecordOutbound newRecord = new() + { + OutboundNo = outboundNo, + BatchNo = parm.BatchNo, + Operator = parm.Operator, + MaterialCode = mmInventory.MaterialCode, + MaterialName = mmInventory.MaterialName, + SupplierCode = mmInventory.SupplierCode, + SupplierName = mmInventory.SupplierName, + LocationCode = mmInventory.LocationCode, + LocationName = mmInventory.LocationName, + WarehouseCode = mmInventory.WarehouseCode, + WarehouseName = mmInventory.WarehouseName, + + //TODO 待调整(可能涉及记录汇总) + Quantity = -delta, + Unit = parm.Unit, + CreatedTime = nowDate, + TransactionType = parm.TransactionType, + Workorder = parm.Workorder, + WorkorderRaw = parm.WorkorderRaw, + OrderNo = parm.OrderNo, + Remarks = parm.Remarks, + }; + Context.Insertable(newRecord).ExecuteCommand(); + Context.Ado.CommitTran(); + return "ok"; + } - var outboundNo = GenerateReceiptNo("CK"); - MmRecordOutbound newRecord = new() - { - OutboundNo = outboundNo, - BatchNo = parm.BatchNo, - Operator = parm.Operator, - MaterialCode = mmMaterial.MaterialCode, - MaterialName = mmMaterial.MaterialName, - LocationCode = mmLocation.LocationCode, - LocationName = mmLocation.LocationName, - WarehouseCode = mmLocation.WarehouseCode, - WarehouseName = mmLocation.WarehouseName, - - //TODO 待调整(可能涉及记录汇总) - Quantity = -delta, - Unit = parm.Unit, - CreatedTime = nowDate, - TransactionType = parm.TransactionType, - Workorder = parm.Workorder, - WorkorderRaw = parm.WorkorderRaw, - OrderNo = parm.OrderNo, - Remarks = parm.Remarks, - }; - Context.Insertable(newRecord).ExecuteCommand(); - Context.Ado.CommitTran(); - return "ok"; + } catch (Exception ex) { @@ -1047,7 +1135,10 @@ namespace DOAN.Service.BZFM Context.Insertable(newRecord).ExecuteCommand(); // 更新工单和订单信息 - if (!string.IsNullOrEmpty(parm.CustomerOrder) && !string.IsNullOrEmpty(parm.Workorder)) + if ( + !string.IsNullOrEmpty(parm.CustomerOrder) + && !string.IsNullOrEmpty(parm.Workorder) + ) { // 获取当前工单信息 var workorderInfo = Context @@ -1081,10 +1172,12 @@ namespace DOAN.Service.BZFM .First(); if (orderPurchase != null) { - int newQuantity = Context - .Queryable() - .Where(it => it.CustomerOrder == parm.CustomerOrder) - .Sum(it => it.ShipmentNum) ?? 0; + int newQuantity = + Context + .Queryable() + .Where(it => it.CustomerOrder == parm.CustomerOrder) + .Sum(it => it.ShipmentNum) + ?? 0; orderPurchase.DeliveryQuantity = newQuantity; if (orderPurchase.DeliveryQuantity > orderPurchase.DemandQuantity) diff --git a/DOAN.Service/MES/Product/IService/IProWorkorderMaterialService.cs b/DOAN.Service/MES/Product/IService/IProWorkorderMaterialService.cs index 189717a..cb72f8f 100644 --- a/DOAN.Service/MES/Product/IService/IProWorkorderMaterialService.cs +++ b/DOAN.Service/MES/Product/IService/IProWorkorderMaterialService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using DOAN.Model.MES.order.Dto; using DOAN.Model.MES.product.Dto; namespace DOAN.Service.MES.product.IService @@ -28,5 +29,54 @@ namespace DOAN.Service.MES.product.IService /// 工单号 /// 出货清单数据 List GetShipmentList(string workorder); + + /// + /// 根据工单号查询物料库存接口 + /// + /// 工单号 + /// 物料库存信息列表 + List GetMaterialInventoryList(string workorder); + + /// + /// 根据工单领料 + /// + /// 领料请求参数 + /// 操作结果 + bool TakeMaterial(MaterialTakeRequestDto request); + + /// + /// 根据工单成品入库 + /// + /// 成品入库请求参数 + /// 操作结果 + bool StoreProduct(ProductStorageRequestDto request); + + /// + /// 根据工单出货 + /// + /// 出货请求参数 + /// 操作结果 + bool ShipProduct(ShipmentRequestDto request); + + /// + /// 根据工单号获取可领料工单清单 + /// + /// 工单号 + /// 可领料工单清单 + List GetPickableWorkordersByWorkorder(string workorder); + + /// + /// 根据工单号获取可出货订单清单 + /// + /// 工单号 + /// 可出货订单清单 + List GetShippableOrdersByWorkorder(string workorder); + + /// + /// 根据工单号查询成品库存 + /// + /// 工单号 + /// 成品库存信息列表 + List GetProductInventoryList(string workorder); } } diff --git a/DOAN.Service/MES/Product/ProWorkorderMaterialService.cs b/DOAN.Service/MES/Product/ProWorkorderMaterialService.cs index 36b3af9..da84699 100644 --- a/DOAN.Service/MES/Product/ProWorkorderMaterialService.cs +++ b/DOAN.Service/MES/Product/ProWorkorderMaterialService.cs @@ -1,9 +1,16 @@ using System.Collections.Generic; using DOAN.Model.BZFM; +using DOAN.Model.MES.order; +using DOAN.Model.MES.order.Dto; using DOAN.Model.MES.product; using DOAN.Model.MES.product.Dto; +using DOAN.Model.Mobile.Dto; using DOAN.Service.MES.product.IService; +using DOAN.Service.Mobile; using Infrastructure.Attribute; +using MailKit.Search; +using Microsoft.IdentityModel.Tokens; +using SqlSugar.DistributedSystem.Snowflake; namespace DOAN.Service.MES.product { @@ -19,7 +26,7 @@ namespace DOAN.Service.MES.product IProWorkorderMaterialService { /// - /// 根据工单号查询领料清单 + /// 根据工单号查询工单已领料清单 /// /// 工单号 /// 领料清单数据 @@ -32,8 +39,11 @@ namespace DOAN.Service.MES.product .Where(it => it.Remarks != "已撤销") .Select(it => new MaterialTakeDto { + Id = it.Id, MaterialCode = it.MaterialCode, MaterialName = it.MaterialName, + SupplierCode = it.SupplierCode, + SupplierName = it.SupplierName, BatchNo = it.BatchNo, Quantity = it.Quantity, Unit = it.Unit, @@ -48,7 +58,7 @@ namespace DOAN.Service.MES.product } /// - /// 根据工单号查询成品入库清单 + /// 根据工单号查询工单已成品入库清单 /// /// 工单号 /// 成品入库清单数据 @@ -61,6 +71,7 @@ namespace DOAN.Service.MES.product .Where(it => it.Remarks != "已撤销") .Select(it => new ProductStorageDto { + Id = it.Id, MaterialCode = it.MaterialCode, MaterialName = it.MaterialName, BatchNo = it.BatchNo, @@ -77,7 +88,7 @@ namespace DOAN.Service.MES.product } /// - /// 根据工单号查询出货清单 + /// 根据工单号查询工单已出货清单 /// /// 工单号 /// 出货清单数据 @@ -90,6 +101,7 @@ namespace DOAN.Service.MES.product .Where(it => it.Remarks != "已撤销") .Select(it => new ShipmentDto { + Id = it.Id, MaterialCode = it.MaterialCode, MaterialName = it.MaterialName, BatchNo = it.BatchNo, @@ -105,5 +117,443 @@ namespace DOAN.Service.MES.product .ToList(); return result; } + + /// + /// 根据工单查询物料库存接口 + /// + /// 工单号 + /// 物料库存信息列表 + public List GetMaterialInventoryList(string workorder) + { + try + { + // 参数验证 + if (string.IsNullOrEmpty(workorder)) + { + throw new ArgumentNullException(nameof(workorder), "工单号不能为空"); + } + + var workorderInfo = Context + .Queryable() + .First(it => it.Workorder == workorder); + if (workorderInfo == null) + { + throw new ArgumentException("工单号不存在", nameof(workorder)); + } + var result = new List(); + // 单原材料 + if (workorderInfo.RouteCode != "10") + { + var materialCode = workorderInfo.MaterialCode; + var InventoryList = Context + .Queryable() + .Where(it => it.MaterialCode == materialCode) + .Where(it => it.LocationCode == "YCL001") + .Where(it => it.CurrentQty > 0) + .Select(it => new MaterialInventoryDto + { + MaterialId = it.Id, + MaterialCode = it.MaterialCode, + MaterialName = it.MaterialName, + CurrentQuantity = it.CurrentQty, + SupplierCode = it.SupplierCode, + SupplierName = it.SupplierName, + Unit = it.Unit, + BatchNo = it.BatchNo, + }) + .ToList(); + result = InventoryList; + } + else + { + //组合材料 + var bomList = Context + .Queryable() + .Where(it => it.ParentMaterialCode == workorderInfo.productionCode) + .ToList(); + foreach (MmMaterial mmMaterial in bomList) + { + var InventoryList = Context + .Queryable() + .Where(it => it.MaterialCode == mmMaterial.MaterialCode) + .Where(it => it.SupplierCode == mmMaterial.SupplierCode) + .Where(it => it.LocationCode == "YCL001" || it.LocationCode == "CP001") + .Where(it => it.CurrentQty > 0) + .Select(it => new MaterialInventoryDto + { + MaterialId = it.Id, + MaterialCode = it.MaterialCode, + MaterialName = it.MaterialName, + CurrentQuantity = it.CurrentQty, + SupplierCode = it.SupplierCode, + SupplierName = it.SupplierName, + Unit = it.Unit, + BatchNo = it.BatchNo, + }) + .ToList(); + result.AddRange(InventoryList); + } + } + + return result; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("查询物料库存失败", ex); + throw; + } + } + + /// + /// 工单领料接口 + /// + /// 领料请求参数 + /// 操作结果 + public bool TakeMaterial(MaterialTakeRequestDto request) + { + try + { + // 参数验证 + if (request == null) + { + throw new ArgumentNullException(nameof(request), "领料请求参数不能为空"); + } + + if (string.IsNullOrEmpty(request.Workorder)) + { + throw new ArgumentNullException(nameof(request.Workorder), "工单号不能为空"); + } + + if (request.Quantity <= 0) + { + throw new ArgumentException("领料数量必须大于0", nameof(request.Quantity)); + } + + var materialInventory = Context + .Queryable() + .First(it => it.Id == request.MaterialInventoryId); + if (materialInventory == null) + { + throw new ArgumentNullException( + nameof(request.MaterialInventoryId), + "物料库存ID查询失败" + ); + } + // 业务逻辑实现部分留空待后续补充 + // 此处应实现验证库存是否充足,更新库存数量,记录领料记录 + ReportFlowService _reportFlowService = new ReportFlowService(); + string workorder = request.Workorder; + string workorderRaw = request.WorkorderRaw; + int processId = 10; + int finishNum = (int)request.Quantity; + string stoveCode = request.StoveCode; + string feedOrder = materialInventory.BatchNo; + string worker = request.Operator; + var result = _reportFlowService.FeedProcessReportwork( + workorder, + processId, + finishNum, + stoveCode, + feedOrder, + worker, + workorderRaw, + materialInventory.Id + ); + // 示例返回true + return result; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("领料操作失败", ex); + throw; + } + } + + /// + /// 工单成品入库接口 + /// + /// 成品入库请求参数 + /// 操作结果 + public bool StoreProduct(ProductStorageRequestDto request) + { + try + { + // 参数验证 + if (request == null) + { + throw new ArgumentNullException(nameof(request), "成品入库请求参数不能为空"); + } + + if (string.IsNullOrEmpty(request.Workorder)) + { + throw new ArgumentNullException(nameof(request.Workorder), "工单号不能为空"); + } + + if (request.Quantity <= 0) + { + throw new ArgumentException("成品数量必须大于0", nameof(request.Quantity)); + } + + var workorderInfo = Context + .Queryable() + .First(it => it.Workorder == request.Workorder); + if (workorderInfo == null) + { + throw new ArgumentException("工单不存在", nameof(request.Workorder)); + } + ReportFlowService _reportFlowService = new ReportFlowService(); + string workorder = request.Workorder; + int processId = 70; + int finishNum = (int)request.Quantity; + int badNum = 0; + string worker = request.Operator; + var result = _reportFlowService.ProcessReportWork( + workorder, + processId, + finishNum, + badNum, + worker + ); + // 示例返回true + return result; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("成品入库操作失败", ex); + throw; + } + } + + /// + /// 工单出货接口 + /// + /// 出货请求参数 + /// 操作结果 + public bool ShipProduct(ShipmentRequestDto request) + { + try + { + // 参数验证 + if (request == null) + { + throw new ArgumentNullException(nameof(request), "出货请求参数不能为空"); + } + + if (string.IsNullOrEmpty(request.Workorder)) + { + throw new ArgumentNullException(nameof(request.Workorder), "工单号不能为空"); + } + + if (string.IsNullOrEmpty(request.OrderId)) + { + throw new ArgumentNullException(nameof(request.OrderId), "订单ID不能为空"); + } + + // 业务逻辑实现部分留空待后续补充 + // 此处应实现验证库存是否充足,更新库存状态,记录出货信息 + OrderPurchase orderPurchase = Context + .Queryable() + .Where(o => o.Id == request.OrderId) + .First(); + + ReportFlowService _reportFlowService = new ReportFlowService(); + string workorder = request.Workorder; + int processId = 90; + int finishNum = (int)request.Quantity; + int badNum = 0; + string customerOrder = orderPurchase.OrderNoMes; + string worker = request.Operator; + var result = _reportFlowService.ShipmentProcessReportwork( + workorder, + processId, + finishNum, + badNum, + customerOrder, + worker + ); + return result == 1; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("出货操作失败", ex); + throw; + } + } + + /// + /// 根据工单号获取可领料工单清单(产成品领取半成品) + /// + /// 工单号 + /// 可领料工单清单 + public List GetPickableWorkordersByWorkorder(string workorder) + { + try + { + // 参数验证 + if (string.IsNullOrEmpty(workorder)) + { + throw new ArgumentNullException(nameof(workorder), "工单号不能为空"); + } + + var workorderInfo = Context + .Queryable() + .First(it => it.Workorder == workorder); + if (workorderInfo == null) + { + throw new ArgumentException("工单不存在", nameof(workorder)); + } + // 需要领取半成品 + if (workorderInfo.RouteCode == "10") + { + return Context + .Queryable() + .LeftJoin((mri,pro)=>mri.Workorder == pro.Workorder) + .Where((mri, pro) => mri.MaterialCode == workorderInfo.MaterialCode) + .Where((mri, pro) => mri.TransactionType == "生产入库") + .Where((mri, pro) => mri.Remarks != "已撤销") + //.Where((mri, pro) => pro.ShipmentNum < pro.PlanNum) + .OrderByDescending((mri, pro) => mri.Workorder) + .Select( + (mri, pro) => new ProWorkorderDto + { + Id = pro.Id, + Workorder = mri.Workorder, + productionName = mri.MaterialCode, + productionCode = mri.MaterialName, + MaterialCode = mri.MaterialCode, + MaterialName = mri.MaterialName, + ShipmentNum = pro.ShipmentNum ?? 0, + PlanNum = pro.PlanNum ?? 0, + Remark01 = mri.Remarks + }, + true + ) + .Take(30) + .ToList(); + } + else + { + // 非10线则返回库存 + + // 示例返回空列表 + return new List(); + } + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("获取可领料工单清单失败", ex); + throw; + } + } + + /// + /// 根据工单号获取可出货订单清单 + /// + /// 工单号 + /// 可出货订单清单 + public List GetShippableOrdersByWorkorder(string workorder) + { + try + { + // 参数验证 + if (string.IsNullOrEmpty(workorder)) + { + throw new ArgumentNullException(nameof(workorder), "工单号不能为空"); + } + + var workorderInfo = Context + .Queryable() + .First(it => it.Workorder == workorder); + if (workorderInfo == null) + { + throw new ArgumentException("工单不存在", nameof(workorder)); + } + var orderPurchaseList = Context + .Queryable() + .Where(o => o.MaterialCode == workorderInfo.productionCode) + .Where(it => it.Orderindicator == 0) + .OrderBy(it => it.DeliveryDate) + .Select( + o => new OrderPurchaseDto + { + Id = o.Id, + OrderNoMes = o.OrderNoMes, + MaterialCode = o.MaterialCode, + MaterialName = o.MaterialName, + DemandQuantity = o.DemandQuantity, + DeliveryQuantity = o.DeliveryQuantity, + DeliveryDate = o.DeliveryDate, + }, + true + ) + .ToList(); + + // 示例返回空列表 + return orderPurchaseList; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("获取可出货订单清单失败", ex); + throw; + } + } + + /// + /// 根据工单号查询成品库存 + /// + /// 工单号 + /// 成品库存信息列表 + public List GetProductInventoryList(string workorder) + { + try + { + // 参数验证 + if (string.IsNullOrEmpty(workorder)) + { + throw new ArgumentNullException(nameof(workorder), "工单号不能为空"); + } + + var workorderInfo = Context + .Queryable() + .First(it => it.Workorder == workorder); + if (workorderInfo == null) + { + throw new ArgumentException("工单不存在", nameof(workorder)); + } + var result = Context + .Queryable() + .Where(it => it.MaterialCode == workorderInfo.productionCode) + .Where(it => it.LocationCode == "CP001") + .Where(it => it.CurrentQty > 0) + .Select(it => new MaterialInventoryDto + { + MaterialId = it.Id, + MaterialCode = it.MaterialCode, + MaterialName = it.MaterialName, + CurrentQuantity = it.CurrentQty, + SupplierCode = it.SupplierCode, + SupplierName = it.SupplierName, + Unit = it.Unit, + BatchNo = it.BatchNo, + }) + .OrderByDescending(it => it.BatchNo) + .Take(10) + .ToList(); + + return result; + } + catch (Exception ex) + { + // 集成现有系统的日志记录 + // Log.Error("查询成品库存失败", ex); + throw; + } + } } } diff --git a/DOAN.Service/Mobile/IService/IReportFlowService.cs b/DOAN.Service/Mobile/IService/IReportFlowService.cs index 25ff50a..0efab90 100644 --- a/DOAN.Service/Mobile/IService/IReportFlowService.cs +++ b/DOAN.Service/Mobile/IService/IReportFlowService.cs @@ -14,7 +14,7 @@ public interface IReportFlowService: IBaseService ProReportwork01 GetProcessReportWorkDetail(string workorder, int process); - bool FeedProcessReportwork(string workorder, int processId, int finish_num, string stove_code, string feed_order, string Worker); + bool FeedProcessReportwork(string workorder, int processId, int finish_num, string stove_code, string feed_order, string Worker, string workorderRaw = "", int inventoryId = -1); bool ProcessReportWork(string workorder, int process, int finish_num,int bad_num,string Worker); diff --git a/DOAN.Service/Mobile/ReportFlowService.cs b/DOAN.Service/Mobile/ReportFlowService.cs index 0dc4bce..d273325 100644 --- a/DOAN.Service/Mobile/ReportFlowService.cs +++ b/DOAN.Service/Mobile/ReportFlowService.cs @@ -51,6 +51,8 @@ public class ReportFlowService : BaseService, IReportFlowServic /// /// /// + /// 原材料工单号 + /// 领料库存id /// public bool FeedProcessReportwork( string workorder, @@ -58,12 +60,30 @@ public class ReportFlowService : BaseService, IReportFlowServic int finish_num, string stove_code, string feed_order, - string Worker + string Worker, + string workorderRaw = "", + int inventoryId = -1 ) { try { int result = 0; + + ProWorkorder proWorkorder = Context + .Queryable() + .Where(it => it.Workorder == workorder) + .First(); + if (proWorkorder == null) + { + throw new Exception($"工单不存在,原材料无法出库:{workorder}"); + } + + int routeId = Context + .Queryable() + .Where(it => it.Code == proWorkorder.RouteCode) + .Select(it => it.Id) + .First(); + // 是否首次提交 bool Exist = Context .Queryable() @@ -72,7 +92,7 @@ public class ReportFlowService : BaseService, IReportFlowServic string NickName = Context .Queryable() - .Where(it => it.UserName == Worker) + .Where(it => it.UserName == Worker || it.NickName == Worker) .Select(it => it.NickName) .First(); Worker = string.IsNullOrEmpty(NickName) ? Worker + "|异常人员|" : NickName; @@ -86,7 +106,7 @@ public class ReportFlowService : BaseService, IReportFlowServic .SetColumns(it => it.FinishNum == finish_num) .SetColumns(it => it.Worker == Worker) .SetColumns(it => it.JobDateTime == DateTime.Now) - .SetColumns(it => it.RouteId == 32) + .SetColumns(it => it.RouteId == routeId) .SetColumns(it => it.UpdatedBy == Worker) .SetColumns(it => it.UpdatedTime == DateTime.Now) .ExecuteCommand(); @@ -104,7 +124,7 @@ public class ReportFlowService : BaseService, IReportFlowServic proReportwork01.Workorder = workorder; proReportwork01.ProcessId = processId; proReportwork01.FinishNum = finish_num; - proReportwork01.RouteId = 32; + proReportwork01.RouteId = routeId; proReportwork01.Worker = Worker; proReportwork01.JobDateTime = DateTime.Now; proReportwork01.CreatedBy = Worker; @@ -124,30 +144,82 @@ public class ReportFlowService : BaseService, IReportFlowServic .Where(it => it.TransactionType == "领料出库") .Where(it => it.Remarks != "已撤销") .First(); - ProWorkorder proWorkorder = Context - .Queryable() - .Where(it => it.Workorder == workorder) - .First(); - if (proWorkorder == null) - { - throw new Exception($"工单异常,原材料无法出库:{workorder}"); - } - if (outRecordbound == null) + if (outRecordbound == null || proWorkorder.RouteCode == "10") { + // 根据原材料工单领料的 + if (!string.IsNullOrEmpty(workorderRaw)) + { + // 需要实现累计领料,超出数量需要提示用户 + ProWorkorder proWorkorderRawInfo = Context + .Queryable() + .Where(it => it.Workorder == workorderRaw) + .First(); + if (proWorkorderRawInfo == null) + { + Context.Ado.RollbackTran(); + throw new Exception($"原材料工单不存在,无法出库:{workorderRaw}"); + } + MmRecordInbound inboundRecord = Context + .Queryable() + .Where(it => it.Workorder == workorderRaw) + .Where(it => it.TransactionType == "生产入库") + .Where(it => it.Remarks != "已撤销") + .First(); + if (inboundRecord == null) + { + Context.Ado.RollbackTran(); + throw new Exception($"原材料工单无成品入库记录:{workorderRaw}"); + } + int newShipmentNum = (proWorkorderRawInfo.ShipmentNum ?? 0) + finish_num; + if (newShipmentNum > inboundRecord.Quantity) + { + Context.Ado.RollbackTran(); + throw new Exception( + $"领料数量超出原始工单成品入库数量,请检查:{workorderRaw}" + ); + } + Context + .Updateable() + .Where(it => it.Workorder == workorderRaw) + .SetColumns(it => it.ShipmentNum == newShipmentNum) + .ExecuteCommand(); + inboundRecord.Remarks += $"[已领料{finish_num}]"; + Context.Updateable(inboundRecord).ExecuteCommand(); + } + string supplierCode = string.Empty; + if (inventoryId != -1) + { + supplierCode = + Context + .Queryable() + .Where(it => it.Id == inventoryId) + .Select(it => it.SupplierCode) + .First() + ?? string.Empty; + if (string.IsNullOrEmpty(supplierCode)) + { + Context.Ado.RollbackTran(); + throw new Exception($"库存信息获取异常,请检查库存是否存在:{inventoryId}"); + } + } + OutboundReceiptDto revokeRecepitDto = new() { ReceiptType = 1, + InventoryId = inventoryId, MaterialCode = proWorkorder.MaterialCode, + SupplierCode = supplierCode, BatchNo = feed_order, LocationCode = "YCL001", WarehouseCode = "WH003", OrderNo = proWorkorder.CustomerOrder, Workorder = workorder, + WorkorderRaw = workorderRaw, Operator = Worker, Quantity = finish_num, TransactionType = "领料出库", - Remarks = $"生产领料,工单号:{workorder}", + Remarks = $"生产领料,领取工单号:{workorder},原材料工单号{workorderRaw}", }; MmInventoryService mmInventoryService = new(); string createReceiptresult = mmInventoryService.CreateOutboundReceipt( @@ -202,13 +274,29 @@ public class ReportFlowService : BaseService, IReportFlowServic try { int result = 0; + + ProWorkorder proWorkorder = Context + .Queryable() + .Where(it => it.Workorder == workorder) + .First(); + if (proWorkorder == null) + { + throw new Exception($"工单不存在,原材料无法出库:{workorder}"); + } + + int routeId = Context + .Queryable() + .Where(it => it.Code == proWorkorder.RouteCode) + .Select(it => it.Id) + .First(); + bool Exist = Context .Queryable() .Where(it => it.Workorder == workorder && it.ProcessId == process) .Any(); string NickName = Context .Queryable() - .Where(it => it.UserName == Worker) + .Where(it => it.UserName == Worker || it.NickName == Worker) .Select(it => it.NickName) .First(); Worker = string.IsNullOrEmpty(NickName) ? Worker + "|异常人员|" : NickName; @@ -222,7 +310,7 @@ public class ReportFlowService : BaseService, IReportFlowServic .SetColumns(it => it.FinishNum == finish_num) .SetColumns(it => it.BadNum == bad_num) .SetColumns(it => it.Worker == Worker) - .SetColumns(it => it.RouteId == 32) + .SetColumns(it => it.RouteId == routeId) .SetColumns(it => it.JobDateTime == DateTime.Now) .SetColumns(it => it.UpdatedBy == Worker) .SetColumns(it => it.UpdatedTime == DateTime.Now) @@ -237,7 +325,7 @@ public class ReportFlowService : BaseService, IReportFlowServic proReportwork01.FinishNum = finish_num; proReportwork01.BadNum = bad_num; proReportwork01.Worker = Worker; - proReportwork01.RouteId = 32; + proReportwork01.RouteId = routeId; proReportwork01.JobDateTime = DateTime.Now; proReportwork01.CreatedBy = Worker; proReportwork01.CreatedTime = DateTime.Now; @@ -245,19 +333,14 @@ public class ReportFlowService : BaseService, IReportFlowServic } // XXX TODO 成品入库(临时使用) - + string workorder_raw = workorder; + if (proWorkorder.RouteCode == "10") + { + //TODO 绑定原有工单 + workorder_raw = ""; + } if (process == 70) { - // 成品入库 - ProWorkorder proWorkorder = Context - .Queryable() - .Where(it => it.Workorder == workorder) - .First(); - if (proWorkorder == null) - { - Context.Ado.RollbackTran(); - throw new Exception($"工单异常,无法成品入库:{workorder}"); - } MmRecordInbound inboundRecord = Context .Queryable() .Where(it => it.Workorder == workorder) @@ -278,16 +361,18 @@ public class ReportFlowService : BaseService, IReportFlowServic if (inboundRecord == null) { //做生产入库单 + // 暂时默认成品入库与出库批次号都为000 InboundReceiptDto revokeRecepitDto = new() { ReceiptType = 1, MaterialCode = proWorkorder.productionCode, - BatchNo = proWorkorder.FeedOrder, + BatchNo = "000", LocationCode = "CP001", WarehouseCode = "WH001", SupplierCode = mmMaterial.SupplierCode, StoveCode = proWorkorder.StoveCode, Workorder = workorder, + WorkorderRaw = workorder_raw, Operator = Worker, Quantity = finish_num, TransactionType = "生产入库", @@ -370,13 +455,17 @@ public class ReportFlowService : BaseService, IReportFlowServic string NickName = Context .Queryable() - .Where(it => it.UserName == Worker) + .Where(it => it.UserName == Worker || it.NickName == Worker) .Select(it => it.NickName) .First(); Worker = string.IsNullOrEmpty(NickName) ? Worker + "|异常人员|" : NickName; int result = 0; - + int routeId = Context + .Queryable() + .Where(it => it.Code == workorderInfo.RouteCode) + .Select(it => it.Id) + .First(); // 判断报工信息是否存在 Context.Ado.BeginTran(); // 更新报工信息 @@ -395,7 +484,7 @@ public class ReportFlowService : BaseService, IReportFlowServic FinishNum = finish_num, BadNum = bad_num, Worker = Worker, - RouteId = 32, + RouteId = routeId, JobDateTime = DateTime.Now, CreatedBy = Worker, CreatedTime = DateTime.Now, @@ -422,11 +511,14 @@ public class ReportFlowService : BaseService, IReportFlowServic .First(); if (outboundDto == null) { + // Todo找还有库存的成品库 + + // 暂时默认成品入库与出库批次号都为000 OutboundReceiptDto revokeRecepitDto = new() { ReceiptType = 1, MaterialCode = workorderInfo.productionCode, - BatchNo = workorderInfo.FeedOrder, + BatchNo = "000", LocationCode = "CP001", WarehouseCode = "WH001", OrderNo = customer_order, @@ -459,7 +551,7 @@ public class ReportFlowService : BaseService, IReportFlowServic .SetColumns(it => it.ShipmentNum == finish_num) .SetColumns(it => it.CustomerOrder == customer_order) .ExecuteCommand(); - // 修改采购订单信息 + // 修改采购订单是否完成 int newQuantity = Context .Queryable()