using System.Data; using System.Dynamic; using PadApplication.DB; using PadApplication.Entites.DbModels; using PadApplication.Entites.Dto; using SqlSugar; using DbType = System.Data.DbType; namespace PadApplication.Services; /// /// 物料条码管理服务类 /// 负责处理生产过程中的物料条码生成、更新、删除等操作 /// 主要功能包括: /// 1. 生成物料条码并关联到工单 /// 2. 更新条码数量信息 /// 3. 删除条码记录 /// 4. 验证工单状态和数量限制 /// public class MesInvItemBarcodesManager : Repository { //当前类已经继承了 Repository 增、删、查、改的方法 private readonly WomdaaManager _womdaaManager = new(); // 物料分类数组,用于判断物料类型 private readonly string[] ItemSort = ["A1", "B1", "C1", "D1", "E1", "F2"]; private readonly MesQaItemsDetect02Manager qaItemsDetect02Manager = new(); // 工单状态数组 private readonly string[] statusArray = ["开工", "暂停", "完工"]; /// /// 添加物料条码 /// /// 工单机器信息DTO,包含工单号、打印数量等信息 /// 打印DTO列表,包含条码打印所需的所有信息 /// 当打印数量超过限制、工单不存在、工单未开工等情况下抛出异常 public List AddItemToBarcodes(OrderMachineDto query) { // 验证打印数量和总数是否有效 if (query.PrintQty is null or <= 0) return null; if (query.Count is null or <= 0) return null; // 幂等性检查 - 防重复提交 if (!string.IsNullOrWhiteSpace(query.RequestId)) { // 检查是否已处理过此请求 var existsCount = Db.Queryable() .Where(x => x.RequestId == query.RequestId) .Count(); if (existsCount > 0) { throw new Exception("条码已生成,请勿重复提交"); } } // 执行工单验证 Execute(query); // 获取工单打印信息 var query1 = new OrderMachineDto(); query1.OrderId = query.OrderId; var womdaaPrintById = _womdaaManager.GetWomdaaPrintById(query1); // 验证打印总数是否超过可打印总数 if (query.Count * query.PrintQty > womdaaPrintById.Bqty) throw new Exception("打印总数超过可打印总数"); // 获取工单信息 var womdaa = Db.Queryable() .Where(s => s.Daa001 == query.orderNo) .First(); if (womdaa == null) throw new Exception("工单单号不存在"); // 验证工单状态是否允许打印 if (Array.IndexOf(statusArray, womdaa.Daa018) == -1) throw new Exception("工单未开工,不能打印条码,请先开工!!!"); // 获取标准包装数 var mesItemsPackageQty = Db.Queryable() .Where(a => a.ItemCode == womdaa.Daa002).First(); if (mesItemsPackageQty == null) throw new Exception("请维护标准包装数!"); // 检查工单状态 womdaa.State ??= "F"; if ("C".Equals(womdaa.State)) throw new Exception("工单已结案!"); // 获取首检信息 var findSjByOrderNo = qaItemsDetect02Manager.FindSJByOrderNo(query); if (findSjByOrderNo == null) throw new Exception("没有查询到首检单"); //if (!"合格".Equals(findSjByOrderNo.FcheckResu) || !"特采使用".Equals(findSjByOrderNo.FcheckResu)) if ("不合格".Equals(findSjByOrderNo.FcheckResu)) throw new Exception("首检不合格,不允许报工"); // 计算已打印总数 var sum = Db.Queryable() .Where(s => s.PbillNo == womdaa.Daa001) .Sum(s => s.Quantity); // 验证打印数量是否超出工单数量 var aa = query.Count * query.PrintQty; if (aa + sum > womdaa.Daa008) throw new Exception("打印数量超出工单数量!"); // 初始化返回列表 var list = new List(); var barcodes = new List(); // 循环生成条码 for (var i = 0; i < query.Count; i++) { // 获取物料信息 var mesItems2 = Db.Queryable() .Where(b => b.ItemNo == womdaa.Daa002 && b.AddressCode == "ALL") .First(); if (mesItems2 == null) throw new Exception("物料信息不存在该物料编码,请维护!"); // 获取工序信息 var womcaa = Db.Queryable() .Where(c => c.Caa001 == womdaa.Daa029).First(); womcaa.IsGy ??= 0; // 验证是否是最后一道工序 if (womcaa.IsGy == 1) { var maxProc = Db.Queryable() .Where(a => a.Daa029 == womdaa.Daa029) .Select(a => SqlFunc.AggregateMax(SqlFunc.ToDecimal(a.ProcNum))) .Single(); if (Convert.ToDecimal(womdaa.ProcNum) != maxProc) throw new Exception("工序工单只有最后一道可以打印条码!"); } // 设置批次号 var lotNo = ""; if (Array.IndexOf(ItemSort, mesItems2) > -1) lotNo = womdaa.LotNo; // 设置条码类型 var typeCode = 25; if (womdaa.Daa001.StartsWith("HSA") || womdaa.Daa001.StartsWith("HSB")) typeCode = 16; // 获取条码类型信息 var mesBarcodeType = Db.Queryable() .Where(d => d.TypeCode == typeCode && d.Factory == "10000" && d.Company == "1000").First(); // 获取当前日期 var cIndate = DateTime.Now.ToString("yyyyMMdd"); // 获取部门信息 var sysDepartment = Db.Queryable() .Where(e => e.Departmentcode == womdaa.DepartmentNo).First(); var Departmentname = womdaa.DepartmentNo; if (sysDepartment != null) Departmentname = sysDepartment.Departmentname; var now = DateTime.Now.ToString("yyyy-MM-dd"); var print = query.PrintQty; // 调用存储过程获取条码 var barcodeResult = SpGetBarcode2("1000", "1000", mesBarcodeType.Id, womdaa.Daa002 + cIndate, womdaa.Daa002 + cIndate, 0); string serial = barcodeResult.Value; string poBarcodeComand = barcodeResult.Msg; if (!string.IsNullOrEmpty(poBarcodeComand)) return null; // 生成物料条码 var itemBarCode = womdaa.Daa002 + "-B" + cIndate + serial; // 构建打印DTO var printDto = new PrintDto { Out1 = Departmentname, //生产部门 Out2 = womdaa.Daa002, //物料编码 Out3 = womdaa.Daa003, //物料名称 Out4 = query.user, //报工人 Out5 = womdaa.Daa001.Substring(0, 3) == "XSG" ? womdaa.Daa029 : womdaa.LotNo, //批次号 Out6 = mesItems2.ItemName, //产品型号 Out7 = print + " " + womdaa.Daa005, //条码数量 Out8 = now, //日期 Out9 = "颜色:" + mesItems2.ColorName + ", 图号:" + mesItems2.EngineeringNo + ", 材质:" + mesItems2.Material, //规格型号 Out10 = womcaa.Caa015, //销售单号 Out11 = womdaa.Daa001, //工单号 Out12 = itemBarCode //条码 }; // 验证条码是否已存在 var count = Db.Queryable() .Where(f => f.ItemBarcode == itemBarCode).Count(); if (count != 0) return null; // 分割用户信息 var strings = query.user.Split(':'); // 创建条码实体 var entity = new MesInvItemBarcodes { ItemBarcode = itemBarCode, BillNo = womdaa.Daa001, ItemNo = womdaa.Daa002, Quantity = print, EpFlag = 1, TaskNo = womdaa.Daa021, CreateBy = strings[0], CreateDate = DateTime.Now, LastupdateBy = strings[0], LastupdateDate = DateTime.Now, Mblnr = "", Barcodestatus = 0, Oldqty = print, Unit = womdaa.Daa005, LotDate = now, Memo = "成品入库", SuppNo = "", ItemSname = womdaa.Daa003, Factory = "1000", Company = "1000", TrLotno = cIndate, UrgentFlag = 0, WorkFlg = 1, WorkLine = 1, WorkNo = womdaa.Daa029, ComeFlg = 1, Hbdy = 0, AddressCode = womdaa.AddressCode, PbillNo = womdaa.Daa001, LineNo = 1, RequestId = query.RequestId // 保存请求唯一标识符,用于防重复提交 }; // 创建报工记录 var mesReporting = new MesReporting { CheckType = 0, ItemNoCade = itemBarCode, CreateBy = strings[0], BgDate = DateTime.Now, BgPerson = strings[0], AddressCode = womdaa.AddressCode, MachineNo = womdaa.MachineNo, // BfQty = query.bf, OkQty = print, ItemNo = womdaa.Daa002, BillNo = womdaa.Daa001 }; // 插入报工记录和条码记录 if (Db.Insertable(mesReporting) .IgnoreColumns(true).ExecuteCommand() > 0) { Db.Insertable(entity).IgnoreColumns(true).ExecuteCommand(); UpdateAmount(mesReporting, query1); } list.Add(printDto); barcodes.Add(entity); } // 更新条码数量 UpdateBarcodeAmount(barcodes); return list; } /// /// 更新报工数量信息 /// /// 报工记录 /// 工单机器信息 public bool AddBFToBarcodes(OrderMachineDto query) { var womdaa = Db.Queryable() .Where(s => s.Daa001 == query.orderNo) .First(); if (womdaa == null) throw new Exception("工单单号不存在"); // 创建报工记录 var mesReporting = new MesReporting { CheckType = 1, // ItemNoCade = itemBarCode, // CreateBy = strings[0], BgDate = DateTime.Now, // BgPerson = strings[0], AddressCode = womdaa.AddressCode, MachineNo = womdaa.MachineNo, BfQty = query.bf, // OkQty = print, ItemNo = womdaa.Daa002, BillNo = womdaa.Daa001, BgPerson = query.staffNo // 新增:报工人编号 }; // 插入报工记录和条码记录 return Db.Insertable(mesReporting) .IgnoreColumns(true).ExecuteCommand() > 0; } /// /// 更新报工数量信息 /// /// 报工记录 /// 工单机器信息 private void UpdateAmount(MesReporting mesReporting, OrderMachineDto query) { // 获取已打印数据 var DyQty = Db.Queryable() .Where(s => s.Id == query.OrderId).Select(s => s.SQuantity).First(); var s1 = DateTime.Now.ToString("yyyy-MM-dd"); // 获取数采数据 var CjQty = Db.Queryable() .Where(s => s.MachineNo == mesReporting.MachineNo && s.EditDate == s1) .OrderByDescending(s => s.CjTiem) .Select(s => s.CjNum).First(); // 获取锚点数据 var anchors = Db.Queryable() .Where(a => a.OrderId == query.OrderId) // && a.EditDate == s1 .OrderByDescending(a => a.EditDate) .First() ?? new MesAnchors { InitialValue = 0, Qty = 0 }; // 计算各种数量 var jt = CjQty; var ljcj = CjQty - anchors.InitialValue; var anchorsQty = anchors.Qty ?? 0; var BlQty = (ljcj + anchorsQty) - DyQty; var bfQty = BlQty; // 获取上一次报工记录 var reporting = Db.Queryable() .Where(a => a.BillNo == mesReporting.BillNo && a.ItemNoCade != mesReporting.ItemNoCade) .OrderByDescending(a => a.Id) .First(); if (reporting != null) bfQty = BlQty - Convert.ToDecimal(reporting.BlQty); // 更新报工记录 Db.Updateable() .SetColumns(a => a.BlQty == BlQty.ToString()) .SetColumns(a => a.CsQty == anchors.InitialValue.ToString()) .SetColumns(a => a.JtQty == jt.ToString()) // .SetColumns(a => a.BfQty == bfQty) .SetColumns(a => a.CjQty == ljcj.ToString()) .SetColumns(a => a.DyQty == DyQty.ToString()) .Where(a => a.ItemNoCade == mesReporting.ItemNoCade) .ExecuteCommand(); } /// /// 更新条码数量 /// /// 条码列表 /// 更新是否成功 private bool UpdateBarcodeAmount(List barcodesList) { // 验证条码列表是否有效 if (barcodesList == null || !barcodesList.Any()) return true; // 获取条码列表 var list = barcodesList.Select(s => s.ItemBarcode).ToList(); // 查询条码记录 var mesInvItemBarcodesList = Db.Queryable() .Where(a => list.Contains(a.ItemBarcode)).ToList(); if (mesInvItemBarcodesList == null || mesInvItemBarcodesList.Count == 0) return true; // 使用事务更新数据 UseTransaction(db => { var billNos = mesInvItemBarcodesList.Select(p => p.PbillNo) .Distinct().ToList(); var executeCommand = 0; // 更新每个工单的数量 foreach (var billNo in billNos) { var sum = db.Queryable() .Where(s => s.PbillNo == billNo) .Sum(s => s.Oldqty); executeCommand += db.Updateable() .SetColumns(x => x.Daa011 == sum) .Where(x => x.Daa001 == billNo) .ExecuteCommand(); } if (executeCommand < 1) throw new Exception("更新条码失败"); return executeCommand; }); return true; } /// /// 执行工单验证 /// 验证工单的发料情况、数量限制等 /// /// 工单机器信息 /// 当工单发料未齐套、报工数量超过限制等情况下抛出异常 private void Execute(OrderMachineDto query) { // 查询工单发料比例 var sql = string.Format( "SELECT nvl(B3.LLQT, 0) FROM WOMDAA A LEFT JOIN (SELECT round(min(case when nvl(B2.DAB022, 0) = 0 then 0 WHEN NVL(B2.DAB007, 0) / B2.DAB022 * NVL(B2.DAB023, 0) > A2.DAA008 then A2.daa008 when b2.DAB020 = 4 then A2.Daa008 ELSE NVL(B2.DAB007, 0) / B2.DAB022 * NVL(B2.DAB023, 0) end), 2) LLQT, B2.DAB001, B2.PID FROM WOMDAB B2 left join WOMDAA A2 on A2.id = B2.pid where nvl(B2.Dab006, 0) <> 0 GROUP BY B2.DAB001, B2.PID) B3 on B3.PID = A.ID WHERE A.DAA001 = '{0}'", query.orderNo); var sqlQuerySingle = Db.Ado.SqlQuerySingle(sql); // 验证工单发料是否齐套 if (sqlQuerySingle is null or 0) throw new Exception("工单发料未齐套!"); // 计算打印数量 var c_quantity = query.Count * query.PrintQty; // 获取工单信息 var womdaa = Db.Queryable() .Where(s => s.Daa001 == query.orderNo).First(); // 验证报工数量是否超过发料比例 if (c_quantity + womdaa.Daa011 > sqlQuerySingle) throw new Exception("报工数量超过工单发料比例,请联系领导或班长通知发料!"); // 验证首检 if (womdaa.FType == 0 && !new[] { "23", "24", "25", "26", "27", "28" }.Contains( womdaa.MachineNo)) { var cNum = Db.Queryable() .Where(a => a.Ftype == "首检" && a.Ismodify1 == 1 && a.Aufnr == query.orderNo) .Count(); if (cNum == 0) throw new Exception("工单未首检,报工失败,请联系品质检验!"); } } /// /// 更新条码数量 /// /// 工单机器信息 /// 更新是否成功 public bool UpdateBarcodeAmount(OrderMachineDto query) { // 验证条码数组是否有效 if (query.barcodes == null || query.barcodes.Length == 0) return true; // 查询条码记录 var mesInvItemBarcodesList = Db.Queryable() .Where(a => query.barcodes.Contains(a.ItemBarcode)).ToList(); if (mesInvItemBarcodesList == null || mesInvItemBarcodesList.Count == 0) return true; // 分割用户信息 var strings = query.user.Split(':'); // 使用事务更新数据 UseTransaction(db => { // 更新条码记录 var executeCommand = db.Updateable() .SetColumns(s => s.CreateBy == strings[0]) .Where(s => query.barcodes.Contains(s.ItemBarcode)) .ExecuteCommand(); if (executeCommand <= 0) return 0; // 获取地址代码和工单号 var addressCodes = mesInvItemBarcodesList.Select(p => p.AddressCode) .Distinct().ToList(); var billNos = mesInvItemBarcodesList.Select(p => p.PbillNo) .Distinct().ToList(); // 更新报工记录 executeCommand += db.Updateable() .SetColumns(s => s.CreateBy == strings[0]) .SetColumns(s => s.BgPerson == strings[0]) .Where(s => addressCodes.Contains(s.AddressCode) && billNos.Contains(s.BillNo) && query.barcodes.Contains(s.ItemNoCade)) .ExecuteCommand(); // 更新工单数量 foreach (var billNo in billNos) { var sum = db.Queryable() .Where(s => s.PbillNo == billNo) .Sum(s => s.Oldqty); executeCommand += db.Updateable() .SetColumns(x => x.Daa011 == sum) .Where(x => x.Daa001 == billNo) .ExecuteCommand(); } if (executeCommand <= 2) throw new Exception("更新条码失败"); return executeCommand; }); return true; } /// /// 删除条码记录 /// /// 工单机器信息 /// 删除是否成功 public bool DeleteBarcode(OrderMachineDto query) { // 验证条码数组是否有效 if (query.barcodes == null || query.barcodes.Length == 0) return true; // 查询条码记录 var mesInvItemBarcodesList = Db.Queryable() .Where(a => query.barcodes.Contains(a.ItemBarcode)).ToList(); if (mesInvItemBarcodesList == null || mesInvItemBarcodesList.Count == 0) return true; // 获取地址代码和工单号 var addressCodes = mesInvItemBarcodesList.Select(p => p.AddressCode) .Distinct().ToList(); var billNos = mesInvItemBarcodesList.Select(p => p.PbillNo) .Distinct().ToList(); var itemNos = mesInvItemBarcodesList.Select(p => p.ItemNo) .Distinct().ToList(); // 查询报工记录 var mesReportings = Db.Queryable() .Where(s => addressCodes.Contains(s.AddressCode) && billNos.Contains(s.BillNo) && itemNos.Contains(s.ItemNo) && query.barcodes.Contains(s.ItemNoCade)).ToList(); if (mesReportings == null || mesReportings.Count == 0) return true; // 使用事务删除数据 UseTransaction(db => { var decimals = mesInvItemBarcodesList.Select(s => s.Id).ToArray(); var executeCommand = db.Deleteable() .In(decimals).ExecuteCommand(); // 删除报工记录 if (mesReportings.Count == query.barcodes.Length) { var array = mesReportings.Select(s => s.Id).ToArray(); executeCommand += db.Deleteable() .In(array).ExecuteCommand(); } else { var array = mesReportings.Take(query.barcodes.Length) .Select(s => s.Id).ToArray(); executeCommand += db.Deleteable() .In(array).ExecuteCommand(); } if (executeCommand < 1) throw new Exception("删除条码失败"); return executeCommand; }); return true; } /// /// 检查是否可以打印条码 /// /// 工单机器信息 /// 可打印的数量,-1表示不可打印 /// 当剩余打印次数为0时抛出异常 private int isPrint(OrderMachineDto query) { // 获取打印相关数据 var womdaaPrint = _womdaaManager.GetWomdaaPrintById(query); var totalItems = womdaaPrint.Bqty; // 总数量 var boxSize = womdaaPrint.Qqty; // 每箱的数量 var remainingPrintableTimes = womdaaPrint.RmiPrQty; // 剩余可打印次数 var maxPrintableTimes = womdaaPrint.Icount; //总打印条码张数 // 验证数据有效性 if (!totalItems.HasValue || !boxSize.HasValue || !remainingPrintableTimes.HasValue || !maxPrintableTimes.HasValue) return -1; if (maxPrintableTimes <= 0) return -1; // 根据剩余打印次数判断 switch (remainingPrintableTimes) { case <= 0: throw new Exception("剩余打印次数为 0,停止打印。"); // 计算下一次打印的数量 // 判断是否是最后一次打印 case 1: { // 如果是最后一次,使用尾数 var printedItems = totalItems.Value - (maxPrintableTimes - 1) * boxSize.Value; return (int)printedItems; } default: return (int)boxSize; } } /// /// 调用存储过程获取条码 /// /// 工厂代码 /// 公司代码 /// 条码类型ID /// 任务编号 /// 日期 /// 是否提交标志 /// 包含条码值和消息的动态对象 /// 当存储过程执行失败时抛出异常 private dynamic SpGetBarcode2(string p0, string p1, decimal cBid, string cItemNo, string cIndate, int p5) { try { // 定义输出参数 var outputResult = new SugarParameter("PO_VALUE", null, DbType.Int32, ParameterDirection.Output, 4000); var outputMessage = new SugarParameter("PO_MSG", null, DbType.String, ParameterDirection.Output, 4000); // 定义输入参数 var parameters = new List { new("PI_FACTORY", p0, DbType.String, ParameterDirection.Input), new("PI_COMPANY", p1, DbType.String, ParameterDirection.Input), new("P_BARCODE_TYPE_ID", cBid, DbType.String, ParameterDirection.Input), new("P_TASK_NO", cItemNo, DbType.String, ParameterDirection.Input), new("P_TASK_ITEM", cIndate, DbType.String, ParameterDirection.Input), new("P_IF_COMMIT", p5, DbType.String, ParameterDirection.Input), outputResult, outputMessage }; // 执行存储过程 Db.Ado.ExecuteCommand( "BEGIN SP_GET_BARCODE2(:PI_FACTORY, :PI_COMPANY, :P_BARCODE_TYPE_ID, :P_TASK_NO, :P_TASK_ITEM, :P_IF_COMMIT, :PO_VALUE, :PO_MSG); END;", parameters.ToArray()); // 获取输出参数值 var resultValue = outputResult.Value?.ToString(); var messageValue = outputMessage.Value?.ToString(); // 返回动态对象 dynamic m = new ExpandoObject(); m.Value = resultValue; m.Msg = messageValue; return m; } catch (Exception ex) { throw new Exception(ex.Message); } } }