diff --git a/.gitignore b/.gitignore index e0566a8..60bb5cc 100644 --- a/.gitignore +++ b/.gitignore @@ -272,3 +272,4 @@ __pycache__/ /Quartz.NET.WindowsService /DOANAdmin-vue /DOAN.Admin.WebApi/DOANModel.xml +/.trae diff --git a/DOAN.Admin.WebApi/Controllers/MES/Quality/IPQC/QcScrapRecordsController.cs b/DOAN.Admin.WebApi/Controllers/MES/Quality/IPQC/QcScrapRecordsController.cs index 98606dc..1005290 100644 --- a/DOAN.Admin.WebApi/Controllers/MES/Quality/IPQC/QcScrapRecordsController.cs +++ b/DOAN.Admin.WebApi/Controllers/MES/Quality/IPQC/QcScrapRecordsController.cs @@ -48,7 +48,7 @@ namespace DOAN.Admin.WebApi.Controllers.BZFM public IActionResult GetQcScrapRecords(long Id) { var response = _QcScrapRecordsService.GetInfo(Id); - + var info = response.Adapt(); return SUCCESS(info); } @@ -91,12 +91,75 @@ namespace DOAN.Admin.WebApi.Controllers.BZFM [HttpPost("delete/{ids}")] [ActionPermissionFilter(Permission = "qcscraprecords:delete")] [Log(Title = "报废记录表", BusinessType = BusinessType.DELETE)] - public IActionResult DeleteQcScrapRecords([FromRoute]string ids) + public IActionResult DeleteQcScrapRecords([FromRoute] string ids) { var idArr = Tools.SplitAndConvert(ids); return ToResponse(_QcScrapRecordsService.Delete(idArr)); } + /// + /// 创建报废单 + /// + /// + /// + [HttpPost("scrap-order")] + [ActionPermissionFilter(Permission = "qcscraprecords:add")] + [Log(Title = "创建报废单", BusinessType = BusinessType.INSERT)] + public IActionResult CreateScrapOrder([FromBody] QcScrapRecordsDto parm) + { + var modal = parm.Adapt().ToCreate(HttpContext); + var response = _QcScrapRecordsService.CreateScrapOrder(modal); + return SUCCESS(response); + } + + /// + /// 创建转用单 + /// + /// + /// + [HttpPost("transfer-order")] + [ActionPermissionFilter(Permission = "qcscraprecords:add")] + [Log(Title = "创建转用单", BusinessType = BusinessType.INSERT)] + public IActionResult CreateTransferOrder([FromBody] QcScrapRecordsDto parm) + { + if (string.IsNullOrEmpty(parm.Workorder)) + { + return ToResponse(StatusCodes.Status400BadRequest, "工单号不能为空"); + } + + var modal = parm.Adapt().ToCreate(HttpContext); + var response = _QcScrapRecordsService.CreateTransferOrder(modal); + return SUCCESS(response); + } + + /// + /// 审批报废记录 + /// + /// 记录ID + /// 审批信息 + /// + [HttpPut("approve/{id}")] + [ActionPermissionFilter(Permission = "qcscraprecords:approve")] + [Log(Title = "审批报废记录", BusinessType = BusinessType.UPDATE)] + public IActionResult ApproveScrapRecord([FromRoute] long id, [FromBody] ScrapApproveDto parm) + { + var response = _QcScrapRecordsService.ApproveScrapRecord(id, parm.IsApproved, parm.Approver); + return ToResponse(response); + } + + /// + /// 撤销报废记录 + /// + /// 记录ID + /// + [HttpPut("revoke/{id}")] + [ActionPermissionFilter(Permission = "qcscraprecords:revoke")] + [Log(Title = "撤销报废记录", BusinessType = BusinessType.UPDATE)] + public IActionResult RevokeScrapRecord([FromRoute] long id) + { + var response = _QcScrapRecordsService.RevokeScrapRecord(id); + return ToResponse(response); + } } } \ No newline at end of file diff --git a/DOAN.Model/MES/Quality/IPQC/Dto/QcScrapRecordsDto.cs b/DOAN.Model/MES/Quality/IPQC/Dto/QcScrapRecordsDto.cs index d4458e5..62159b9 100644 --- a/DOAN.Model/MES/Quality/IPQC/Dto/QcScrapRecordsDto.cs +++ b/DOAN.Model/MES/Quality/IPQC/Dto/QcScrapRecordsDto.cs @@ -12,6 +12,13 @@ namespace DOAN.Model.BZFM.Dto public string BatchNo { get; set; } public DateTime? StartTime { get; set; } public DateTime? EndTime { get; set; } + + public string ScrapOrderNo { get; set; } + public string StoveCode { get; set; } + public string SupplierCode { get; set; } + public string ScrapType { get; set; } + public string LineCode { get; set; } + public string Status { get; set; } } /// @@ -25,15 +32,12 @@ namespace DOAN.Model.BZFM.Dto public long? TenantId { get; set; } - [Required(ErrorMessage = "更新时间不能为空")] public DateTime? UpdatedTime { get; set; } public long? UpdatedBy { get; set; } - [Required(ErrorMessage = "创建时间不能为空")] public DateTime? CreatedTime { get; set; } - [Required(ErrorMessage = "创建人ID不能为空")] public long CreatedBy { get; set; } public string Remark { get; set; } @@ -55,7 +59,6 @@ namespace DOAN.Model.BZFM.Dto public string Operator { get; set; } - [Required(ErrorMessage = "主键ID不能为空")] public long Id { get; set; } public string DisposalMethod { get; set; } @@ -73,6 +76,7 @@ namespace DOAN.Model.BZFM.Dto public string MaterialName { get; set; } + [Required(ErrorMessage = "物料编码不能为空")] public string MaterialCode { get; set; } public string ProductName { get; set; } @@ -85,9 +89,11 @@ namespace DOAN.Model.BZFM.Dto public string Workorder { get; set; } - [Required(ErrorMessage = "报废单号不能为空")] public string ScrapOrderNo { get; set; } + public string SupplierCode { get; set; } + + public string SupplierName { get; set; } [ExcelColumn(Name = "状态:草稿,待审批,已批准,已拒绝")] diff --git a/DOAN.Model/MES/Quality/IPQC/Dto/ScrapApproveDto.cs b/DOAN.Model/MES/Quality/IPQC/Dto/ScrapApproveDto.cs new file mode 100644 index 0000000..d7a17cc --- /dev/null +++ b/DOAN.Model/MES/Quality/IPQC/Dto/ScrapApproveDto.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DOAN.Model.BZFM.Dto +{ + /// + /// 报废审批DTO + /// + public class ScrapApproveDto + { + /// + /// 是否批准 + /// + public bool IsApproved { get; set; } + + /// + /// 审批人 + /// + public string Approver { get; set; } + } +} \ No newline at end of file diff --git a/DOAN.Model/MES/Quality/IPQC/QcScrapRecords.cs b/DOAN.Model/MES/Quality/IPQC/QcScrapRecords.cs index eabffa4..5ec2def 100644 --- a/DOAN.Model/MES/Quality/IPQC/QcScrapRecords.cs +++ b/DOAN.Model/MES/Quality/IPQC/QcScrapRecords.cs @@ -186,6 +186,18 @@ namespace DOAN.Model.BZFM /// [SugarColumn(ColumnName = "scrap_order_no")] public string ScrapOrderNo { get; set; } + + /// + /// 供应商编码 + /// + [SugarColumn(ColumnName = "supplier_code")] + public string SupplierCode { get; set; } + + /// + /// 供应商名称 + /// + [SugarColumn(ColumnName = "supplier_name")] + public string SupplierName { get; set; } } } \ No newline at end of file diff --git a/DOAN.Service/MES/Material/MmInventoryService.cs b/DOAN.Service/MES/Material/MmInventoryService.cs index 565b679..52879a5 100644 --- a/DOAN.Service/MES/Material/MmInventoryService.cs +++ b/DOAN.Service/MES/Material/MmInventoryService.cs @@ -81,6 +81,10 @@ namespace DOAN.Service.BZFM !string.IsNullOrEmpty(parm.MaterialCode), m => m.MaterialCode.Contains(parm.MaterialCode) ) + .AndIF( + !string.IsNullOrEmpty(parm.SupplierCode), + m => m.SupplierCode.Contains(parm.SupplierCode) + ) .AndIF( !string.IsNullOrEmpty(parm.WarehouseName), m => m.WarehouseName.Contains(parm.WarehouseName) @@ -93,10 +97,6 @@ namespace DOAN.Service.BZFM !string.IsNullOrEmpty(parm.LocationCode), m => m.LocationCode.Contains(parm.LocationCode) ) - .AndIF( - !string.IsNullOrEmpty(parm.SupplierCode), - m => m.SupplierCode.Contains(parm.SupplierCode) - ) .AndIF( !string.IsNullOrEmpty(parm.SupplierName), m => m.SupplierName.Contains(parm.SupplierName) @@ -734,7 +734,7 @@ namespace DOAN.Service.BZFM CreatedTime = it.CreatedTime, Workorder = it.Workorder, StoveCode = it.StoveCode, - Remarks = it.Remarks + Remarks = it.Remarks, }) .OrderByDescending(it => it.CreatedTime) .ToPage(parm); @@ -777,7 +777,7 @@ namespace DOAN.Service.BZFM CreatedTime = it.CreatedTime, Workorder = it.Workorder, OrderNo = it.OrderNo, - Remarks = it.Remarks + Remarks = it.Remarks, }) .OrderByDescending(it => it.CreatedTime) .ToPage(parm); diff --git a/DOAN.Service/MES/Quality/IPQC/IService/IQcScrapRecordsService.cs b/DOAN.Service/MES/Quality/IPQC/IService/IQcScrapRecordsService.cs index 673f13f..9136fa4 100644 --- a/DOAN.Service/MES/Quality/IPQC/IService/IQcScrapRecordsService.cs +++ b/DOAN.Service/MES/Quality/IPQC/IService/IQcScrapRecordsService.cs @@ -15,7 +15,36 @@ namespace DOAN.Service.BZFM.IService QcScrapRecords AddQcScrapRecords(QcScrapRecords parm); int UpdateQcScrapRecords(QcScrapRecords parm); - + + /// + /// 创建报废单 + /// + /// + /// + QcScrapRecords CreateScrapOrder(QcScrapRecords parm); + + /// + /// 创建转用单 + /// + /// + /// + QcScrapRecords CreateTransferOrder(QcScrapRecords parm); + + /// + /// 审批报废记录 + /// + /// 记录ID + /// 是否批准 + /// 审批人 + /// + int ApproveScrapRecord(long id, bool isApproved, string approver); + + /// + /// 撤销报废记录 + /// + /// 记录ID + /// + int RevokeScrapRecord(long id); } } diff --git a/DOAN.Service/MES/Quality/IPQC/QcScrapRecordsService.cs b/DOAN.Service/MES/Quality/IPQC/QcScrapRecordsService.cs index 3b952eb..a307fae 100644 --- a/DOAN.Service/MES/Quality/IPQC/QcScrapRecordsService.cs +++ b/DOAN.Service/MES/Quality/IPQC/QcScrapRecordsService.cs @@ -8,7 +8,7 @@ using DOAN.Service.BZFM.IService; namespace DOAN.Service.BZFM { /// - /// 报废记录表Service业务层处理 + /// Service业务层处理 /// [AppService(ServiceType = typeof(IQcScrapRecordsService), ServiceLifetime = LifeTime.Transient)] public class QcScrapRecordsService : BaseService, IQcScrapRecordsService @@ -51,7 +51,15 @@ namespace DOAN.Service.BZFM /// public QcScrapRecords AddQcScrapRecords(QcScrapRecords model) { - return Insertable(model).ExecuteReturnEntity(); + // 如果没有提供报废单号,则生成一个 + if (string.IsNullOrEmpty(model.ScrapOrderNo)) + { + // 根据报废类型选择前缀 + string prefix = model.ScrapType == "转用" ? "ZY" : "BF"; + model.ScrapOrderNo = GenerateScrapOrderNo(prefix); + } + + return Context.Insertable(model).ExecuteReturnEntity(); } /// @@ -71,9 +79,204 @@ namespace DOAN.Service.BZFM /// private static Expressionable QueryExp(QcScrapRecordsQueryDto parm) { - var predicate = Expressionable.Create(); + var predicate = Expressionable + .Create() + // 模糊搜索字段 + .AndIF(!string.IsNullOrEmpty(parm.ScrapOrderNo), it => it.ScrapOrderNo.Contains(parm.ScrapOrderNo)) + .AndIF(!string.IsNullOrEmpty(parm.Workorder), it => it.Workorder.Contains(parm.Workorder)) + .AndIF(!string.IsNullOrEmpty(parm.StoveCode), it => it.StoveCode.Contains(parm.StoveCode)) + .AndIF(!string.IsNullOrEmpty(parm.ProductCode), it => it.ProductCode.Contains(parm.ProductCode)) + .AndIF(!string.IsNullOrEmpty(parm.BatchNo), it => it.BatchNo.Contains(parm.BatchNo)) + // 精确搜索字段 + .AndIF(!string.IsNullOrEmpty(parm.MaterialCode), it => it.MaterialCode == parm.MaterialCode) + .AndIF(!string.IsNullOrEmpty(parm.SupplierCode), it => it.SupplierCode == parm.SupplierCode) + .AndIF(!string.IsNullOrEmpty(parm.ScrapType), it => it.ScrapType == parm.ScrapType) + .AndIF(!string.IsNullOrEmpty(parm.LineCode), it => it.LineCode == parm.LineCode) + .AndIF(!string.IsNullOrEmpty(parm.Status), it => it.Status == parm.Status); return predicate; } + + /// + /// 生成报废单号 + /// + /// 前缀,默认BF表示报废 + /// + private string GenerateScrapOrderNo(string prefix = "BF") + { + var datePart = DateTime.Now.ToString("yyyyMMdd"); + var baseNo = prefix + datePart + "-"; + + // 尝试从报废记录表中获取当天最大的编号后缀 + try + { + var last = Context + .Queryable() + .Where(it => it.ScrapOrderNo.StartsWith(prefix + datePart)) + .OrderByDescending(it => it.ScrapOrderNo) + .Select(it => it.ScrapOrderNo) + .First(); + + if (string.IsNullOrEmpty(last)) + { + return baseNo + "001"; + } + + var suf = last.Substring((prefix + datePart).Length).TrimStart('-', '_'); + if (int.TryParse(suf, out var n)) + { + return baseNo + (n + 1).ToString("D3"); + } + + return baseNo + "001"; + } + catch + { + return baseNo + "001"; + } + } + + /// + /// 创建报废单 + /// + /// + /// + public QcScrapRecords CreateScrapOrder(QcScrapRecords parm) + { + // 验证物料编码 + if (string.IsNullOrEmpty(parm.MaterialCode)) + { + throw new Exception("物料编码不能为空"); + } + + // 生成报废单号 + parm.ScrapOrderNo = GenerateScrapOrderNo(); + + // 设置状态为待审批 + parm.Status = "待审批"; + parm.ScrapType = "报废"; + + return Context.Insertable(parm).ExecuteReturnEntity(); + } + + /// + /// 创建转用单 + /// + /// + /// + public QcScrapRecords CreateTransferOrder(QcScrapRecords parm) + { + // 验证物料编码 + if (string.IsNullOrEmpty(parm.MaterialCode)) + { + throw new Exception("物料编码不能为空"); + } + + // 验证工单号 + if (string.IsNullOrEmpty(parm.Workorder)) + { + throw new Exception("工单号不能为空"); + } + + // 生成报废单号 + parm.ScrapOrderNo = GenerateScrapOrderNo("ZY"); // ZY表示转用 + + // 设置状态为待审批,报废类型为转用 + parm.Status = "待审批"; + parm.ScrapType = "转用"; + + return Context.Insertable(parm).ExecuteReturnEntity(); + } + + /// + /// 审批报废记录 + /// + /// 记录ID + /// 是否批准 + /// 审批人 + /// + public int ApproveScrapRecord(long id, bool isApproved, string approver) + { + int result = 0; + + UseTran2(() => + { + // 获取记录信息 + var record = Context.Queryable().Where(x => x.Id == id).First(); + + if (record == null) + { + throw new Exception("记录不存在"); + } + + // 只有待审批状态的记录才能被审批 + if (record.Status != "待审批") + { + throw new Exception("只有待审批状态的记录才能被审批"); + } + + // 更新审批信息 + var updateObj = new QcScrapRecords + { + Id = id, + Status = isApproved ? "已批准" : "已拒绝", + ApprovalDate = DateTime.Now, + SupervisorName = approver, + UpdatedTime = DateTime.Now + }; + + result = Context.Updateable(updateObj).UpdateColumns(x => new { x.Status, x.ApprovalDate, x.SupervisorName, x.UpdatedTime }).ExecuteCommand(); + + if (isApproved) + { + // 根据报废类型处理 + if (record.ScrapType == "转用") + { + // 转用单批准:生成新工单(这里需要根据实际业务调整工单生成逻辑) + // 注意:需要确保工单服务的命名空间和方法名正确 + // 示例:_proWorkorderService.GenerateWorkorder(record); + } + else + { + // 报废单批准:生成入库单到报废库(这里需要根据实际业务调整入库逻辑) + // 示例:调用入库单服务添加到报废库 + } + } + }); + + return result; + } + + /// + /// 撤销报废记录 + /// + /// 记录ID + /// + public int RevokeScrapRecord(long id) + { + // 获取记录信息 + var record = Context.Queryable().Where(x => x.Id == id).First(); + + if (record == null) + { + throw new Exception("记录不存在"); + } + + // 只有待审批状态的记录才能被撤销 + if (record.Status != "已批准") + { + throw new Exception("只有已批准状态的记录才能被撤销"); + } + + // 撤销:将状态改为待审批 + var updateObj = new QcScrapRecords + { + Id = id, + Status = "待审批", + UpdatedTime = DateTime.Now + }; + + return Context.Updateable(updateObj).UpdateColumns(x => new { x.Status, x.UpdatedTime }).ExecuteCommand(); + } } } \ No newline at end of file