using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using NetTopologySuite.Geometries; using Omu.ValueInjecter; using Volo.Abp; using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Services; using Win_in.Sfs.Basedata.Boms; using Win_in.Sfs.Basedata.Caches; using Win_in.Sfs.Basedata.Domain.Shared; using Win_in.Sfs.Shared.Domain; using Win_in.Sfs.Shared.Domain.Shared; namespace Win_in.Sfs.Basedata.Domain; public class BomManager : DomainService, IBomManager { private readonly IBomRepository _repository; private readonly IItemBasicRepository _itemBasicRepository; public BomManager(IBomRepository repository, IItemBasicRepository itemBasicRepository) { _repository = repository; _itemBasicRepository = itemBasicRepository; InitBomComponent(); } private void InitBomComponent() { int count = _repository.CountAsync().Result; if (Cache.Boms.Count!=count) { Cache.Boms=_repository.ToListAsync().Result; } } /// /// 获取对应的Bom信息 /// /// /// /// /// public virtual async Task> GetRecursiveListAsync(string productItemCode, DateTime validTime, bool isRecursive = true) { List totalBoms = new List(); var boms = await _repository.GetListAsync(p => p.Product == productItemCode && (p.BeginTime <= validTime) && (p.EndTime >= validTime)).ConfigureAwait(false); if (isRecursive) { foreach (var bom in boms) { if (bom.Component == bom.Product) { totalBoms.AddRange(boms); continue; } //获取下级Bom,如果有就继续,没有就完事 await GetListWithValidTimeAsync(totalBoms, bom, validTime, 1).ConfigureAwait(false); } } else { foreach (var bom in boms) { var item = await _itemBasicRepository.FindAsync(p => p.Code == bom.Component).ConfigureAwait(false); if (item is { IsPhantom: true }) { await GetRecursiveListAsync(bom.Component, validTime, isRecursive).ConfigureAwait(false); } else { totalBoms.Add(bom); }; } } return totalBoms; } /// /// 递归获取bom /// /// /// /// /// /// private async Task GetListWithValidTimeAsync(List totalBoms, Bom bom, DateTime validTime, decimal multipleQty) { var subboms = await _repository.GetListAsync(p => p.Product == bom.Product && p.BeginTime <= validTime && p.EndTime >= validTime).ConfigureAwait(false); if (subboms == null || subboms.Count == 0) { //根据bom多层放大倍数,第一次传过来的是1 bom.ComponentQty *= multipleQty; totalBoms.Add(bom); return; } else { foreach (var subbom in subboms) { //获取下级Bom,如果有就继续,没有就完事 await GetListWithValidTimeAsync(totalBoms, subbom, validTime, subbom.ComponentQty * multipleQty).ConfigureAwait(false); } } } /// /// 执行导入 /// public virtual async Task ImportDataAsync(List mergeEntities, List deleteEntities = null) { if (deleteEntities != null && deleteEntities.Count > 0) { await _repository.BulkDeleteAsync(deleteEntities).ConfigureAwait(false); } await _repository.BulkMergeAsync(mergeEntities).ConfigureAwait(false); } /// /// 所有子物料号 /// /// /// public virtual async Task> GetListOfProductAsync(string product) { return await _repository.GetListAsync(p => p.Product == product).ConfigureAwait(false); } public virtual async Task> GetListWithPhantomItemAsync(string productItemCode, string mfgOp, DateTime validTime, bool onlyFromProductionPlan) { var where = BuildExpression(productItemCode, mfgOp, validTime, onlyFromProductionPlan); var entities = await (await _repository.GetDbSetAsync().ConfigureAwait(false)).AsNoTracking().Where(where).ToListAsync().ConfigureAwait(false); var phantomItemBoms = await GetPhantomItemBomsAsync(entities, mfgOp, validTime, onlyFromProductionPlan).ConfigureAwait(false); return phantomItemBoms; } private static Expression> BuildExpression(string productItemCode, string mfgOp, DateTime validTime, bool onlyFromProductionPlan) { Expression> where = p => p.Product == productItemCode // && p.MFGOp == mfgOp && p.ComponentQty > 0 && (p.BeginTime <= validTime) && (p.EndTime >= validTime); if (onlyFromProductionPlan) { where = where.And(p => p.DistributionType == EnumDistributionType.FromProductionPlan); } return where; } private async Task> GetPhantomItemBomsAsync(List productBoms, string mfgOp, DateTime validTime, bool onlyFromProductionPlan) { var result = new List(); foreach (var bom in productBoms) { var item = await _itemBasicRepository.FirstOrDefaultAsync(p => p.Code == bom.Component).ConfigureAwait(false); if (item == null) { throw new UserFriendlyException($"代码为 {bom.Component} 的物品信息不存在."); } if (item.IsPhantom) { var where = BuildExpression(item.Code, mfgOp, validTime, onlyFromProductionPlan); var query = (await _repository.GetDbSetAsync().ConfigureAwait(false)).AsNoTracking().Where(where); Console.WriteLine(query.ToString()); var phantomItemBoms = await query.ToListAsync().ConfigureAwait(false); //递归获取下层BOM的子零件为虚零件的BOM var nextLevelBoms = await GetPhantomItemBomsAsync(phantomItemBoms, mfgOp, validTime, onlyFromProductionPlan).ConfigureAwait(false); result.AddRange(nextLevelBoms); } else { result.Add(bom); } } return result; } /// /// 所有父物料号 /// /// /// public virtual async Task> GetListOfComponentAsync(string component) { return await _repository.GetListAsync(p => p.Component == component).ConfigureAwait(false); } /// /// 根据总成号、总成数量取所有子物料及其汇总数量 /// /// 总成号 /// 总成数量 /// public virtual async Task> GetMaterialTotalQtyAsync(string productCode, int productNum) { if (productNum < 1) { throw new UserFriendlyException("productNum参数值必须大于等于1"); } var lst = await _repository.GetListAsync(p => p.Product == productCode).ConfigureAwait(false); foreach (var item in lst) { item.ComponentQty = item.ComponentQty * productNum; } return lst; } public async Task> GetSubcomponentsRecursiveList(List p_lst, EnumBomSelectedType p_type ) { List list = new List(); foreach (var item in p_lst) { var sublist= await GetSubcomponentsRecursive(item, p_type).ConfigureAwait(false); list.AddRange(sublist); } return list; } /// /// Bom操作 /// /// /// /// public async Task> GetSubcomponentsRecursive(BomComponent p_component, EnumBomSelectedType p_type ) { List lastList = new List(); List dimensionList=new List(); var treeList=await GetSubcomponentsRecursive(p_component, 1, p_component.ComponentQty, p_component.Component, (rs) => lastList.Add(rs) , (rs1)=>{ dimensionList.Add(rs1); }).ConfigureAwait(false); List returnList=new List(); switch (p_type) { case EnumBomSelectedType.Last: returnList = lastList; break; case EnumBomSelectedType.Tree: returnList=treeList; break; case EnumBomSelectedType.Dimension: returnList=dimensionList; break; } return returnList; } /// /// 层级、拆解、一维结构、树状结构 /// /// 上级组件(初始时为根元素) /// 层级一般为1 /// 累计数量 /// 根 /// 拆解到最终零件时 /// 树型转成一维表用 /// /// private async Task> GetSubcomponentsRecursive(BomComponent p_component, int level, decimal sumQty, string root, Action p_actionLast, Action p_actionDimension /* ,List bomList =null*/ ) { List subComponents = new List(); // 假设 GetComponentsByProduct 方法可获取某个物料号下的所有子零件 List directSubComponents =await GetComponentsByProduct(p_component.Component).ConfigureAwait(false); if (!directSubComponents.Any() && level != 1)//不是根元素 { p_actionLast(p_component); } foreach (var component in directSubComponents) { component.Root = root; component.SumQty = sumQty * component.ComponentQty; component.ParentComponent = p_component.Component; component.Level = level; component.Path = (p_component.Component != root) ? p_component.Path + $"->{component.Component}" : p_component.Component + $"->{component.Component}"; component.SubComponents =await GetSubcomponentsRecursive(component, level + 1, sumQty * component.ComponentQty, component.Root, p_actionLast, p_actionDimension).ConfigureAwait(false); p_actionDimension(component); subComponents.Add(component); } return subComponents; } private async Task> GetComponentsByProduct(string product) { List list=new List(); list=Cache.Boms.Count > 0 ? Cache.Boms.Where(p => p.Product == product).ToList() : await _repository.GetListAsync(p => p.Product == product).ConfigureAwait(false); List components = new List(); foreach (var component in list) { BomComponent bomComponent = new BomComponent(); bomComponent.InjectFrom(component); components.Add(bomComponent); } // 其他物料号的子零件信息类似添加 return components; } /// /// 获取所有bomtree /// /// /// public virtual async Task> GetAllItemByCode(string productCode) { List boms = new List(); var lst = await _repository.GetListAsync(p => p.Product == productCode).ConfigureAwait(false); foreach (var bom in lst) { boms.Add(bom); var results= await GetAllItemByCode(bom.Component).ConfigureAwait(false); boms.AddRange(results); } return boms; } }