using MES.Service.DB;
|
using MES.Service.Dto.webApi;
|
using MES.Service.Modes;
|
using MES.Service.util;
|
using SqlSugar;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
|
namespace MES.Service.service;
|
|
/// <summary>
|
/// 收料单数据管理类(处理ERP收料单数据同步到MES收料单表)
|
/// 关联主表:MesInvItemArn,明细表:MesInvItemArnDetail
|
/// 关联ERP DTO:ErpSltz(聚合类)、ErpSltza(ERP主表)、ErpSltzBList(ERP明细)
|
/// </summary>
|
public class MesInvItemArnManager : Repository<MesInvItemArn>
|
{
|
/// <summary>
|
/// 批量保存收料单(主表+明细)- 事务保证批量操作一致性
|
/// </summary>
|
/// <param name="erpSltzList">ERP收料单列表(含主表+明细)</param>
|
/// <returns>全部成功返回true,否则false</returns>
|
public bool SaveList(List<ErpSltz> erpSltzList)
|
{
|
if (erpSltzList == null || !erpSltzList.Any())
|
throw new ArgumentNullException(nameof(erpSltzList), "待保存的收料单列表不能为空");
|
|
// 修复:用事务包裹批量操作,确保数据一致性
|
return UseTransaction(db =>
|
{
|
foreach (var erpSltz in erpSltzList)
|
{
|
// 修复:调用事务内的Save方法,传入db实例
|
if (!Save(db, erpSltz))
|
{
|
return 0; // 单条失败,事务回滚
|
}
|
}
|
return 1; // 全部成功
|
}) > 0;
|
}
|
|
/// <summary>
|
/// 单条保存收料单(主表+明细)- 事务内调用(修正访问修饰符,确保事务内可用)
|
/// </summary>
|
/// <param name="db">事务内的SqlSugar实例</param>
|
/// <param name="erpSltz">ERP收料单(含主表+明细)</param>
|
/// <returns>单条处理成功返回true</returns>
|
private bool Save(SqlSugarScope db, ErpSltz erpSltz)
|
{
|
// 1. 参数校验
|
if (erpSltz == null)
|
throw new ArgumentNullException(nameof(erpSltz), "收料单数据不能为空");
|
if (erpSltz.ErpSltza == null)
|
throw new ArgumentNullException(nameof(erpSltz.ErpSltza), "收料单主表数据不能为空");
|
|
// 2. 提取ERP主表和明细数据
|
var erpMain = erpSltz.ErpSltza;
|
var erpDetails = erpSltz.ErpSltzBList ?? new List<ErpSltzBList>();
|
|
// 3. 修复:用事务内的db查询,确保数据一致性
|
Guid mainId = GetOrCreateMainId(db, erpMain);
|
|
// 4. 映射ERP数据到MES实体(修复字段注释,补充关键属性)
|
var mesMain = MapErpSltzaToMesInvItemArn(erpMain, mainId);
|
var mesDetails = MapErpSltzBListToMesInvItemArnDetail(erpDetails, mainId);
|
|
// 5. 根据操作类型处理数据
|
switch (erpMain.TYPE?.Trim())
|
{
|
case "1": // 新增
|
case "2": // 更新
|
return HandleSaveOrUpdate(db, mesMain, mesDetails, mainId);
|
case "3": // 删除
|
return HandleDelete(db, mesMain, mesDetails, mainId);
|
default:
|
throw new NotImplementedException($"未实现的收料单操作类型:{erpMain.TYPE}(支持类型:1-新增,2-更新,3-删除)");
|
}
|
}
|
|
/// <summary>
|
/// 单条保存收料单(主表+明细)- 对外公开接口(供控制器调用)
|
/// </summary>
|
/// <param name="erpSltz">ERP收料单数据(含主表+明细)</param>
|
/// <returns>保存成功返回true</returns>
|
public bool Save(ErpSltz erpSltz)
|
{
|
if (erpSltz == null)
|
throw new ArgumentNullException(nameof(erpSltz), "收料单数据不能为空");
|
if (erpSltz.ErpSltza == null)
|
throw new ArgumentNullException(nameof(erpSltz.ErpSltza), "收料单主表数据不能为空");
|
|
// 事务内处理主从表保存
|
return UseTransaction(db =>
|
{
|
return Save(db, erpSltz) ? 1 : 0;
|
}) > 0;
|
}
|
|
/// <summary>
|
/// 提前获取或生成MES主表ID(修复:用事务内db查询)
|
/// </summary>
|
private Guid GetOrCreateMainId(SqlSugarScope db, ErpSltza erpMain)
|
{
|
if (string.IsNullOrEmpty(erpMain.billNo))
|
throw new ArgumentException("ERP收料单单据号不能为空,无法确定主表唯一性", nameof(erpMain.billNo));
|
|
// 修复:用事务内的db查询,而非Context
|
var existingMain = db.Queryable<MesInvItemArn>()
|
.Where(m => m.BillNo == erpMain.billNo)
|
.First();
|
|
return existingMain != null
|
? existingMain.Id
|
: Guid.NewGuid();
|
}
|
|
/// <summary>
|
/// 处理收料单新增/更新(主表+明细)
|
/// </summary>
|
private bool HandleSaveOrUpdate(SqlSugarScope db, MesInvItemArn mesMain, List<MesInvItemArnDetail> mesDetails, Guid mainId)
|
{
|
mesMain.Id = mainId;
|
bool isMainExist = db.Queryable<MesInvItemArn>().Where(m => m.Id == mainId).Any();
|
int mainOperateResult;
|
|
if (isMainExist)
|
{
|
mainOperateResult = db.Updateable(mesMain)
|
.IgnoreColumns(m => new { m.CreateDate })
|
.Where(m => m.Id == mainId)
|
.ExecuteCommand();
|
}
|
else
|
{
|
mesMain.CreateDate = DateTime.Now;
|
mainOperateResult = db.Insertable(mesMain).ExecuteCommand();
|
}
|
|
// 处理明细
|
int deleteOldDetailResult = db.Deleteable<MesInvItemArnDetail>()
|
.Where(d => d.Mid == mainId)
|
.ExecuteCommand();
|
|
int insertNewDetailResult = mesDetails.Count > 0
|
? db.Insertable(mesDetails).ExecuteCommand()
|
: 1;
|
|
return mainOperateResult > 0 && (deleteOldDetailResult >= 0 && insertNewDetailResult > 0);
|
}
|
|
/// <summary>
|
/// 处理收料单删除(主表+明细)
|
/// </summary>
|
private bool HandleDelete(SqlSugarScope db, MesInvItemArn mesMain, List<MesInvItemArnDetail> mesDetails, Guid mainId)
|
{
|
db.Deleteable<MesInvItemArnDetail>().Where(d => d.Mid == mainId).ExecuteCommand();
|
int mainDeleteResult = db.Deleteable<MesInvItemArn>().Where(m => m.Id == mainId).ExecuteCommand();
|
return mainDeleteResult >= 0;
|
}
|
|
/// <summary>
|
/// ERP主表映射到MES主表(修复:取消关键字段注释,修正FType逻辑)
|
/// </summary>
|
private MesInvItemArn MapErpSltzaToMesInvItemArn(ErpSltza erpMain, Guid mainId)
|
{
|
// 单据日期转换
|
DateTime.TryParse(erpMain.FDate, out DateTime parsedDate);
|
// 是否SRM转换(0-否,1-是)
|
int.TryParse(erpMain.F_ZJXF_sfgx, out int isSrm);
|
// 供应商ID转换(字符串直接赋值,匹配MES字段类型)
|
string suppId = string.IsNullOrEmpty(erpMain.SupplierId) ? null : erpMain.SupplierId.Trim();
|
// 修复:“是否委外”逻辑(假设ERP的fType是“1”=是,“0”=否,或bool字符串)
|
bool isOutsourcing = false;
|
if (!string.IsNullOrEmpty(erpMain.fType))
|
{
|
isOutsourcing = erpMain.fType.Trim() == "1" || erpMain.fType.Trim().Equals("true", StringComparison.OrdinalIgnoreCase);
|
}
|
|
return new MesInvItemArn
|
{
|
// 修复:取消关键字段注释,补充赋值
|
Id = mainId,
|
BillNo = erpMain.billNo?.Trim() ?? throw new ArgumentException("收料单单据号不能为空"),
|
SuppId = suppId,
|
CreateDate = parsedDate == DateTime.MinValue ? null : (DateTime?)parsedDate,
|
Remark = erpMain.Remark?.Trim(),
|
IsSrm = isSrm,
|
EbelnK3id = erpMain.erpId?.Trim(), // ERP主表ID(对应ebeln_k3id)
|
CreateBy = erpMain.createBy?.Trim() ?? "SYSTEM", // 默认为系统
|
FType = isOutsourcing, // 修复:正确的是否委外逻辑
|
ReceiveOrgId = erpMain.ReceiveOrgId?.Trim(),
|
// LastUpdateUser = erpMain.FCreatorId?.Trim() ?? "SYSTEM",
|
// LastUpdateTime = DateTime.Now,
|
// IsOut = false, // 初始未出库
|
// Status = false // 初始未审核
|
};
|
}
|
|
/// <summary>
|
/// ERP明细映射到MES明细(修复:取消关键字段注释,修正EbelnK3id转换)
|
/// </summary>
|
private List<MesInvItemArnDetail> MapErpSltzBListToMesInvItemArnDetail(List<ErpSltzBList> erpDetails, Guid mainId)
|
{
|
return erpDetails.Select(erpDetail =>
|
{
|
// 数值类型安全转换
|
int.TryParse(erpDetail.LineNo, out int lineNo); // 明细主键
|
int.TryParse(erpDetail.ProductCode, out int itemId); // 物料编码
|
decimal.TryParse(erpDetail.PurchaseQty, out decimal purchaseQty); // 采购订单数量
|
decimal.TryParse(erpDetail.DeliveryQty, out decimal deliveryQty); // 本次应收数量
|
decimal.TryParse(erpDetail.IncludeQty, out decimal includeQty); // 本次实收数量
|
// 修复:用采购单ID字段(ebeln_k3id)转int,而非源单单号
|
int.TryParse(erpDetail.FSrcBillNo, out int ebelnK3id);
|
int.TryParse(erpDetail.FSrcBillLine, out int lineK3id); // 采购单行ID
|
bool.TryParse(erpDetail.urgentFlag, out bool urgentFlag); // 急料标识
|
|
return new MesInvItemArnDetail
|
{
|
// 修复:取消关键字段注释,补充赋值
|
// LineNo = lineNo, // 明细主键(必须赋值)
|
Mid = mainId, // 外键(关联主表ID,必须赋值)
|
Ebeln = erpDetail.FBillNo?.Trim(), // 采购单号
|
ItemId = itemId,
|
EbelnQty = purchaseQty,
|
SubQty = deliveryQty,
|
Quantity = includeQty,
|
// PurchaseUnit = erpDetail.PurchaseUnit?.Trim(), // 采购单位(补充赋值)
|
// InventoryUnit = erpDetail.InventoryUnit?.Trim(), // 库存单位(补充赋值)
|
Memo = erpDetail.Remark?.Trim(),
|
EbelnK3id = ebelnK3id, // 修复:正确的采购单ID转换
|
LineK3id = lineK3id,
|
// SalesOrderId = erpDetail.SalesOrderId?.Trim(), // 销售订单号(补充赋值)
|
// FMtoNo = erpDetail.FMtoNo?.Trim(), // 计划跟踪号(补充赋值)
|
// FLot = erpDetail.FLot?.Trim(), // 批号(补充赋值)
|
UrgentFlag = urgentFlag
|
//FStockId = erpDetail.DepotId?.Trim() // 收货仓库编号
|
};
|
}).ToList();
|
}
|
|
/// <summary>
|
/// 按单据号查询MES收料单(主表+明细)
|
/// </summary>
|
public (MesInvItemArn main, List<MesInvItemArnDetail> details) GetByBillNo(string billNo)
|
{
|
if (string.IsNullOrEmpty(billNo))
|
throw new ArgumentNullException(nameof(billNo), "查询条件单据号不能为空");
|
|
var main = Context.Queryable<MesInvItemArn>()
|
.Where(m => m.BillNo == billNo)
|
.First();
|
|
var details = main != null
|
? Context.Queryable<MesInvItemArnDetail>()
|
.Where(d => d.Mid == main.Id)
|
.ToList()
|
: new List<MesInvItemArnDetail>();
|
|
return (main, details);
|
}
|
}
|