feat(报废管理): 实现报废单和转用单的创建与审批流程
添加报废审批DTO和供应商字段 实现创建报废单/转用单功能 新增审批和撤销报废记录接口 优化查询条件并生成唯一报废单号
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -272,3 +272,4 @@ __pycache__/
|
||||
/Quartz.NET.WindowsService
|
||||
/DOANAdmin-vue
|
||||
/DOAN.Admin.WebApi/DOANModel.xml
|
||||
/.trae
|
||||
|
||||
@@ -98,5 +98,68 @@ namespace DOAN.Admin.WebApi.Controllers.BZFM
|
||||
return ToResponse(_QcScrapRecordsService.Delete(idArr));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建报废单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("scrap-order")]
|
||||
[ActionPermissionFilter(Permission = "qcscraprecords:add")]
|
||||
[Log(Title = "创建报废单", BusinessType = BusinessType.INSERT)]
|
||||
public IActionResult CreateScrapOrder([FromBody] QcScrapRecordsDto parm)
|
||||
{
|
||||
var modal = parm.Adapt<QcScrapRecords>().ToCreate(HttpContext);
|
||||
var response = _QcScrapRecordsService.CreateScrapOrder(modal);
|
||||
return SUCCESS(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建转用单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
[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<QcScrapRecords>().ToCreate(HttpContext);
|
||||
var response = _QcScrapRecordsService.CreateTransferOrder(modal);
|
||||
return SUCCESS(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 审批报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <param name="parm">审批信息</param>
|
||||
/// <returns></returns>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 撤销报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <returns></returns>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -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 = "状态:草稿,待审批,已批准,已拒绝")]
|
||||
|
||||
24
DOAN.Model/MES/Quality/IPQC/Dto/ScrapApproveDto.cs
Normal file
24
DOAN.Model/MES/Quality/IPQC/Dto/ScrapApproveDto.cs
Normal file
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 报废审批DTO
|
||||
/// </summary>
|
||||
public class ScrapApproveDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否批准
|
||||
/// </summary>
|
||||
public bool IsApproved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 审批人
|
||||
/// </summary>
|
||||
public string Approver { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -187,5 +187,17 @@ namespace DOAN.Model.BZFM
|
||||
[SugarColumn(ColumnName = "scrap_order_no")]
|
||||
public string ScrapOrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 供应商编码
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "supplier_code")]
|
||||
public string SupplierCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 供应商名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "supplier_name")]
|
||||
public string SupplierName { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -16,6 +16,35 @@ namespace DOAN.Service.BZFM.IService
|
||||
QcScrapRecords AddQcScrapRecords(QcScrapRecords parm);
|
||||
int UpdateQcScrapRecords(QcScrapRecords parm);
|
||||
|
||||
/// <summary>
|
||||
/// 创建报废单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
QcScrapRecords CreateScrapOrder(QcScrapRecords parm);
|
||||
|
||||
/// <summary>
|
||||
/// 创建转用单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
QcScrapRecords CreateTransferOrder(QcScrapRecords parm);
|
||||
|
||||
/// <summary>
|
||||
/// 审批报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <param name="isApproved">是否批准</param>
|
||||
/// <param name="approver">审批人</param>
|
||||
/// <returns></returns>
|
||||
int ApproveScrapRecord(long id, bool isApproved, string approver);
|
||||
|
||||
/// <summary>
|
||||
/// 撤销报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <returns></returns>
|
||||
int RevokeScrapRecord(long id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using DOAN.Service.BZFM.IService;
|
||||
namespace DOAN.Service.BZFM
|
||||
{
|
||||
/// <summary>
|
||||
/// 报废记录表Service业务层处理
|
||||
/// Service业务层处理
|
||||
/// </summary>
|
||||
[AppService(ServiceType = typeof(IQcScrapRecordsService), ServiceLifetime = LifeTime.Transient)]
|
||||
public class QcScrapRecordsService : BaseService<QcScrapRecords>, IQcScrapRecordsService
|
||||
@@ -51,7 +51,15 @@ namespace DOAN.Service.BZFM
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,9 +79,204 @@ namespace DOAN.Service.BZFM
|
||||
/// <returns></returns>
|
||||
private static Expressionable<QcScrapRecords> QueryExp(QcScrapRecordsQueryDto parm)
|
||||
{
|
||||
var predicate = Expressionable.Create<QcScrapRecords>();
|
||||
var predicate = Expressionable
|
||||
.Create<QcScrapRecords>()
|
||||
// 模糊搜索字段
|
||||
.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成报废单号
|
||||
/// </summary>
|
||||
/// <param name="prefix">前缀,默认BF表示报废</param>
|
||||
/// <returns></returns>
|
||||
private string GenerateScrapOrderNo(string prefix = "BF")
|
||||
{
|
||||
var datePart = DateTime.Now.ToString("yyyyMMdd");
|
||||
var baseNo = prefix + datePart + "-";
|
||||
|
||||
// 尝试从报废记录表中获取当天最大的编号后缀
|
||||
try
|
||||
{
|
||||
var last = Context
|
||||
.Queryable<QcScrapRecords>()
|
||||
.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";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建报废单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建转用单
|
||||
/// </summary>
|
||||
/// <param name="parm"></param>
|
||||
/// <returns></returns>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 审批报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <param name="isApproved">是否批准</param>
|
||||
/// <param name="approver">审批人</param>
|
||||
/// <returns></returns>
|
||||
public int ApproveScrapRecord(long id, bool isApproved, string approver)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
UseTran2(() =>
|
||||
{
|
||||
// 获取记录信息
|
||||
var record = Context.Queryable<QcScrapRecords>().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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 撤销报废记录
|
||||
/// </summary>
|
||||
/// <param name="id">记录ID</param>
|
||||
/// <returns></returns>
|
||||
public int RevokeScrapRecord(long id)
|
||||
{
|
||||
// 获取记录信息
|
||||
var record = Context.Queryable<QcScrapRecords>().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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user