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; public class MesCgthSqManager : Repository { /// /// 批量保存采购退货单(主表+明细) /// public bool SaveList(List erpCgthList) { if (erpCgthList == null || !erpCgthList.Any()) throw new ArgumentNullException(nameof(erpCgthList), "待保存的退货单列表不能为空"); // 逐条处理,全部成功才返回true(事务内批量处理更优,此处保持原有逻辑) var result = erpCgthList.Select(Save).ToList(); return result.All(b => b); } /// /// 保存采购退货单(主表+明细) /// public bool Save(ErpCgth erpCgth) { if (erpCgth == null) throw new ArgumentNullException(nameof(erpCgth), "退货单数据不能为空"); if (erpCgth.ErpCgtha == null) throw new ArgumentNullException(nameof(erpCgth.ErpCgtha), "退货单主表数据不能为空"); // 提取主表和明细表DTO var erpMain = erpCgth.ErpCgtha; var erpDetails = erpCgth.ErpCgthBList ?? new List(); // 避免明细为null // 步骤1:映射主表基础数据(暂不处理Id) var mesMain = MapErpCgthaToMesCgthSq(erpMain); // 步骤2:提前确定主表Id(核心修正:在映射明细表前获取/生成Id) Guid mainId = GetOrCreateMainId(mesMain); // 步骤3:用确定的mainId映射明细表(确保Mid=mainId) var mesDetails = MapErpCgthBToMesCgthSqDetail(erpDetails, mainId); // 步骤4:事务内处理主从表保存 return UseTransaction(db => { switch (erpMain.TYPE) { case "1": // 新增 case "2": // 更新 case "4": // 其他新增/更新类型 case "5": // 提交 return SaveOrUpdateData(db, mesMain, mesDetails, mainId) ? 1 : 0; case "3": // 删除 case "6": // 撤销 return DeleteData(db, mesMain, mesDetails, mainId) ? 1 : 0; default: throw new NotImplementedException($"未实现的操作类型:{erpMain.TYPE}"); } }) > 0; } /// /// 提前获取或生成主表Id(确保在映射明细表前确定) /// private Guid GetOrCreateMainId(MesCgthSq mesMain) { // 优先通过单据号查询已有主表(更新场景) var existingMain = Context.Queryable() .Where(m => m.BillNo == mesMain.BillNo) .First(); if (existingMain != null) { // 已存在:返回数据库中的Id return existingMain.Id; } else { // 不存在:生成新Id(新增场景) return Guid.NewGuid(); } } /// /// 新增或更新数据(主表+明细) /// private bool SaveOrUpdateData(SqlSugarScope db, MesCgthSq mesMain, List mesDetails, Guid mainId) { // 绑定主表Id(使用提前确定的mainId) mesMain.Id = mainId; // 处理主表:新增或更新 bool isExist = db.Queryable().Where(m => m.BillNo == mesMain.BillNo).Any(); int mainResult; if (isExist) { // 更新:按Id匹配(避免单据号重复导致错误) mainResult = db.Updateable(mesMain) .IgnoreColumns(m => new { m.CreateDate }) // 不更新创建时间 .Where(m => m.Id == mainId) .ExecuteCommand(); } else { // 新增:使用提前生成的Id mainResult = db.Insertable(mesMain).ExecuteCommand(); } // 处理明细表:先删旧数据,再插新数据(确保数据同步) // 1. 删除当前主表关联的旧明细 int deleteOldDetailResult = db.Deleteable() .Where(d => d.Mid == mainId) .ExecuteCommand(); // 2. 插入新明细(Mid已=mainId) int insertDetailResult = mesDetails.Count > 0 ? db.Insertable(mesDetails).ExecuteCommand() : 1; // 无明细时视为成功 // 校验结果(主表必须成功,明细删除/插入至少有一个成功) return mainResult > 0 && (deleteOldDetailResult >= 0 && insertDetailResult > 0); } /// /// 删除数据(主表+明细) /// private bool DeleteData(SqlSugarScope db, MesCgthSq mesMain, List mesDetails, Guid mainId) { // 1. 删除明细(按主表Id删除) int detailResult = db.Deleteable() .Where(d => d.Mid == mainId) .ExecuteCommand(); // 2. 删除主表(按Id删除) int mainResult = db.Deleteable() .Where(m => m.Id == mainId) .ExecuteCommand(); // 允许明细原本不存在(detailResult=0),但主表必须删除成功 return mainResult > 0; } /// /// 主表映射(仅处理基础字段,Id由GetOrCreateMainId确定) /// private MesCgthSq MapErpCgthaToMesCgthSq(ErpCgtha erpMain) { return new MesCgthSq { // Id暂不赋值(由GetOrCreateMainId后续确定) ErpId = erpMain.ERPID, // ERP主表ID BillNo = erpMain.billNo ?? throw new ArgumentNullException(nameof(erpMain.billNo), "单据编号不能为空"), Type = erpMain.TYPE, FDate = erpMain.FDate, FDocumentStatus = erpMain.FDocumentStatus, FSupplierId = erpMain.FSupplierID, FBillTypeId = erpMain.FBillTypeID, FBusinessType = erpMain.FBusinessType, // 转换ReturnType: A->检验退料, B->库存退料 ReturnType = erpMain.FMRTYPE switch { "A" => "检验退料", "B" => "库存退料", _ => erpMain.FMRTYPE // 保持原值不变 }, // 转换ReturnMethod: A->退料补料, B->退料扣款 ReturnMethod = erpMain.FMRMODE switch { "A" => "退料补料", "B" => "退料并扣款", _ => erpMain.FMRMODE // 保持原值不变 }, CreateBy = erpMain.FCreatorId, LastUpdateUser = erpMain.FCreatorId, FPurchaseOrgId = erpMain.FPurchaseOrgId, ThOrgId = erpMain.FStockOrgId, FRequireOrgId = erpMain.FRequireOrgId, FMRDeptId = erpMain.FMRDeptId, FStockerId = erpMain.FSTOCKERID, FPurchaserId = erpMain.FPURCHASERID, FMRReason = erpMain.FMRREASON, FPurchaseDeptId = erpMain.FPURCHASEDEPTID, FPurchaserGroupId = erpMain.FPURCHASERGROUPID, // 转换FACCTYPE: Q->数量验收, A->金额验收, R->比例验收 FACCTYPE = erpMain.FACCTYPE switch { "Q" => "Q:数量验收", "A" => "A:金额验收", "R" => "R:比例验收", _ => erpMain.FACCTYPE // 保持原值不变 }, FCreateDate = erpMain.FCreateDate, FWPVTINTEGERL6W = 0, // 供应商ID(安全转换) SuppId = !string.IsNullOrEmpty(erpMain.FSupplierID) && int.TryParse(erpMain.FSupplierID, out int suppId) ? suppId : null, Status = false, // 系统字段(创建时间仅新增时赋值,更新时不覆盖) CreateDate = DateTime.Now, LastUpdateTime = DateTime.Now }; } /// /// 明细表映射(使用提前确定的mainId作为Mid) /// private List MapErpCgthBToMesCgthSqDetail(List erpDetails, Guid mainId) { return erpDetails.Select(erpDetail => new MesCgthSqDetail { Mid = mainId, // 直接使用提前确定的mainId(确保非全零) // ERP明细ID(安全转换) ErpId = !string.IsNullOrEmpty(erpDetail.ERPID) && int.TryParse(erpDetail.ERPID, out int erpId) ? erpId : null, // 外部系统ID(安全转换) Eid = !string.IsNullOrEmpty(erpDetail.EID) && int.TryParse(erpDetail.EID, out int eid) ? eid : null, FsrcBillNo = erpDetail.FSRCBillNo, InvBillNo = erpDetail.FSRCBillNo, FsrcBillTypeId = erpDetail.FSRCBillTypeId, // 物料ID(安全转换) ItemId = !string.IsNullOrEmpty(erpDetail.FMATERIALID) && int.TryParse(erpDetail.FMATERIALID, out int itemId) ? itemId : null, FUnitId = erpDetail.FUnitID, // 仓库ID(安全转换) DepotId = !string.IsNullOrEmpty(erpDetail.FSTOCKID) && long.TryParse(erpDetail.FSTOCKID, out long depotId) ? depotId : null, FstockLocId = erpDetail.FSTOCKLOCID, FLot = erpDetail.FLot, SqNum = erpDetail.FRMREALQTY, // 假设FRMREALQTY是数值类型(如decimal) Remark = erpDetail.FNOTE, FMtoNo = erpDetail.FMtoNo, IsFinish = false // 初始未完成 }).ToList(); } }