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);
}
}
}