using Business.Core.MongoDBHelper; using Business.ResourceExamineManagement.Dto; using Bussiness.Model.Production; using Bussiness.Model.Tech; using Bussiness.MongoModel.Production; using Bussiness.MongoModel.Tech; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.Application.Services; using Volo.Abp.Domain.Repositories; namespace Business.ResourceExamineManagement { /// /// 产能检查 /// public class ProductExamineAppService: ApplicationService { #region 服务 /// /// 工艺路径 /// private readonly IMongoDB _mes_technique; /// /// 工序 /// private readonly IMongoDB _mes_process; /// /// 工艺关联工序 /// private readonly IMongoDB _mes_tech_process; /// /// 工作日历 /// private readonly IMongoDB _mes_work_calendar; /// /// 工作日历明细 /// private readonly IMongoDB _mes_work_calendar_list; /// /// 工艺工序关联工位 /// private readonly IMongoDB _mes_tech_proc_workshop; /// /// 排程占用记录 /// private readonly IMongoDB _mes_schedule_occupy; #endregion /// /// 构造函数 /// public ProductExamineAppService( IMongoDB mes_technique, IMongoDB mes_process, IMongoDB mes_tech_process, IMongoDB mes_tech_proc_workshop ) { _mes_technique = mes_technique; _mes_process = mes_process; _mes_tech_process = mes_tech_process; _mes_tech_proc_workshop = mes_tech_proc_workshop; } /// /// 产能计算 /// /// 产能检查入参 /// 生产时长 public async Task ProductiveExamine(ProdExamineParamDto param) { if (param.packages <= 0) { throw new NotImplementedException("产能计算参数有误!"); } #region 1、数据准备 //1.1、获取工艺路径数据 mo_mes_technique tech = _mes_technique.Find(p => p.bom == param.bom_number && p.bomver == param.version && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted).Result.FirstOrDefault(); if (tech == null) { return param.packages * 100; //throw new NotImplementedException("请先配置工艺路径!"); } //1.2、获取工艺路径关联工序数据 List tech_Processes = await _mes_tech_process.GetManyByCondition(p => p.tech_id == tech.mysql_id && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted); if (tech_Processes.Count == 0) { return param.packages * 100; //throw new NotImplementedException("请先配置工序!"); } //1.3、获取当前工艺路径下的工序数据 //FilterDefinition filter = Builders.Filter.In(s => s.Id, tech_Processes.Select(m => m.proc_id).ToList()); //List process = await _mes_process.GetManyByIds(filter); List procIds = tech_Processes.Select(m => m.proc_id.GetValueOrDefault()).ToList(); List process = await _mes_process.GetManyByCondition(p => procIds.Contains(p.mysql_id) && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted); //1.3、获取工艺工序关联工位信息 List techProcIds = tech_Processes.Select(m => m.mysql_id).ToList(); List tech_Proc_Workshops = await _mes_tech_proc_workshop.GetManyByCondition(p => techProcIds.Contains(p.tech_proc_id.Value) && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted); #endregion //1、获取工艺路径下的第一层级工序:目前只考虑第一层级 List fistLevels = tech_Processes.Where(p => p.parentprocid == tech.mysql_id).ToList(); if (fistLevels.Count == 0) { throw new NotImplementedException("当前工艺路径没有配置工序,请调整!"); } //工艺预处理 List teches = TechProcPretreatment(fistLevels,param.packages); decimal sumTimes = teches.OrderByDescending(p => p.sumTimes).First().sumTimes; return sumTimes; } /// /// 工序预处理,按照多分支生成多条单独的工艺路径 /// /// 当前工序 /// 工艺关联工序list /// 生产件数 /// private List TechProcPretreatment(List processes,int packages) { //工艺路径预处理dto List techProcDtos = new List(); TechProcDto dto; //获取下一步工序id List nextProcIds = processes.Where(p=>p.nextprocid != null).Select(p => p.nextprocid.GetValueOrDefault()).ToList(); //获取起点工序 var startProcs = processes.Where(p => !nextProcIds.Contains(p.proc_id.GetValueOrDefault())).ToList(); //递归处理工序返回值 List rtnList; for (int i = 0; i < startProcs.Count; i++) { dto = new TechProcDto(); rtnList = new List(); GetNextProc(startProcs[i], processes, rtnList); dto.serialno = i + 1; dto.processes = rtnList; //dto.details = CalcTakeTimeByLq(rtnList, packages);//通过Lq计算 dto.details = CalcTakeTimeByLqt(rtnList, packages);//通过Lqt计算 dto.sumTimes = dto.details.Sum(p=>p.wait_time); techProcDtos.Add(dto); } return techProcDtos; } /// /// 递归:根据起始工序,获取后续工序 /// /// /// /// private void GetNextProc(mo_mes_tech_process proc, List processes, List rtnList) { rtnList.Add(proc); //下一工序id为null,终止 if (proc?.nextprocid == null) { return; } //获取下一个工序 var nextProc = processes.FirstOrDefault(p=>p.proc_id == proc.nextprocid); if (nextProc == null) { return; } GetNextProc(nextProc, processes, rtnList); } /// /// 通过Lq计算工艺耗时 /// /// /// /// private List CalcTakeTimeByLq(List Processes, int packages) { //工序需要等待时间记录 List starts = new List(); StartTimeDto dto; foreach (var chd in Processes) { dto = new StartTimeDto(); if (chd.nextprocid == null)//最后一个工序 { //计算最后一个工序耗时 dto = CalcProcTakeTimeByLq(chd, packages, packages); } else { dto = CalcProcTakeTimeByLq(chd, chd.lq.GetValueOrDefault(), packages); } //添加记录 starts.Add(dto); } return starts; } /// /// 通过Lq计算当前工序前置准备时间 /// /// /// LeadQuantity to Start Next /// 件数 /// private StartTimeDto CalcProcTakeTimeByLq(mo_mes_tech_process proc, decimal quantity, int packages) { //记录当前工序耗时 StartTimeDto dto = new StartTimeDto(); //添加耗时记录 dto.tech_id = proc.tech_id.GetValueOrDefault(); dto.proc_id = proc.proc_id.GetValueOrDefault(); dto.nextproc_id = proc.nextprocid; if (proc.wctype == 1)//人工型:数量/uph(一小时生产数量)*60(小时转换为分钟)/wsinuse(工位数) { if ( proc.uph.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序uph或wsinuse参数配置错误,请调整!"); } dto.wait_time = quantity / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault(); dto.take_time = packages / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault(); } else if (proc.wctype == 2)//流水线型:数量*ct(生产一件所需时间)/wsinuse(工位数) { if (proc.ct.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序ct或wsinuse参数配置错误,请调整!"); } dto.wait_time = quantity * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault(); dto.take_time = packages * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault(); } else if (proc.wctype == 3)//设备型:向上取整(数量/一次可加工数量/wsinuse(工位数))*ct(老化一次所需时间) { if (proc.upe.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0|| proc.ct.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序upe或ct或wsinuse参数配置错误,请调整!"); } dto.wait_time = Math.Ceiling(quantity / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault(); dto.take_time = Math.Ceiling(packages / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault(); } return dto; } /// /// 通过Lqt计算工艺耗时 /// /// /// /// private List CalcTakeTimeByLqt(List Processes, int packages) { //工序需要等待时间记录 List starts = new List(); StartTimeDto dto; foreach (var chd in Processes) { dto = new StartTimeDto(); //添加耗时记录 dto.tech_id = chd.tech_id.GetValueOrDefault(); dto.proc_id = chd.proc_id.GetValueOrDefault(); dto.nextproc_id = chd.nextprocid; //计算当前工序生产耗时 dto.take_time = CalcProcTakeTime(chd, packages); if (chd.nextprocid == null)//最后一个工序 { dto.wait_time = dto.take_time; } else { dto.wait_time = chd.lqt.Value; } //添加记录 starts.Add(dto); } return starts; } /// /// 计算当前工序生产时间 /// /// /// 件数 /// private decimal CalcProcTakeTime(mo_mes_tech_process proc, int packages) { //当前工序生产时间 decimal takeTiem = 0.00m; if (proc.wctype == 1)//人工型:数量/uph(一小时生产数量)*60(小时转换为分钟)/wsinuse(工位数) { if (proc.uph.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序uph或wsinuse参数配置错误,请调整!"); } takeTiem = packages / proc.uph.GetValueOrDefault() * 60 / proc.wsinuse.GetValueOrDefault(); } else if (proc.wctype == 2)//流水线型:数量*ct(生产一件所需时间)/wsinuse(工位数) { if (proc.ct.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序ct或wsinuse参数配置错误,请调整!"); } takeTiem = packages * proc.ct.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault(); } else if (proc.wctype == 3)//设备型:向上取整(数量/一次可加工数量/wsinuse(工位数))*ct(老化一次所需时间) { if (proc.upe.GetValueOrDefault() == 0 || proc.wsinuse.GetValueOrDefault() == 0 || proc.ct.GetValueOrDefault() == 0) { throw new NotImplementedException("当前工序upe或ct或wsinuse参数配置错误,请调整!"); } takeTiem = Math.Ceiling(packages / proc.upe.GetValueOrDefault() / proc.wsinuse.GetValueOrDefault()) * proc.ct.GetValueOrDefault(); } return takeTiem; } } }