Преглед изворни кода

Merge branch 'master' of http://123.60.180.165:4647/ZZYDOP/DOPCore

heteng пре 3 година
родитељ
комит
52b26da0dd

+ 2132 - 0
MicroServices/Business/Back/在制工单实现/ResourceExamineAppService.cs

@@ -0,0 +1,2132 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Dynamic.Core;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Dtos;
+using Volo.Abp.Domain.Repositories;
+using Business.Models;
+using Microsoft.AspNetCore.Authorization;
+using Business.Permissions;
+using XCZ;
+using Business.ResourceExamineManagement.Dto;
+using Bussiness.Model.MES.IC;
+using AutoMapper.Internal.Mappers;
+using Bussiness.Model.Tech;
+using Bussiness.Model.Production;
+using Business.Core.MongoDBHelper;
+using Business.Core.Utilities;
+using Hangfire.Storage.Monitoring;
+using Business.BookManagement.Dto;
+using Volo.Abp.ObjectMapping;
+using Volo.Abp.Application.Services;
+using ZstdSharp.Unsafe;
+using System.Transactions;
+using NUglify.JavaScript.Syntax;
+using System.Linq.Expressions;
+using XCZ.Extensions;
+using System.ComponentModel;
+using System.Reflection.Emit;
+using NUglify.Helpers;
+using Microsoft.AspNetCore.SignalR.Protocol;
+using System.ComponentModel.Design;
+using Volo.Abp.Validation.StringValues;
+using System.Runtime.CompilerServices;
+using MongoDB.Driver;
+using Volo.Abp.Validation.Localization;
+using Hangfire.Annotations;
+using System.Globalization;
+using MongoDB.Driver.Linq;
+using Bussiness.Model.SRM;
+using System.ComponentModel.DataAnnotations;
+using Bussiness.Model.Sale;
+using Amazon.Runtime.Internal.Transform;
+using System.IO.Compression;
+using System.Collections;
+using System.Data.SqlTypes;
+using Microsoft.EntityFrameworkCore.Diagnostics;
+using Hangfire.Server;
+using WkHtmlToPdfDotNet;
+using Microsoft.EntityFrameworkCore.Migrations.Operations;
+using Microsoft.AspNetCore.SignalR;
+using System.Diagnostics;
+using Newtonsoft.Json;
+
+namespace Business.ResourceExamineManagement
+{
+    /// <summary>
+    /// 资源检查
+    /// </summary>
+    //[Authorize(BusinessPermissions.ResourceExamine.Default)]
+    public class ResourceExamineAppService : ApplicationService, IResourceExamineAppService
+    {
+        #region 服务
+        SnowFlake help = new SnowFlake();
+
+        /// <summary>
+        /// 物料占用记录
+        /// </summary>
+        private readonly IMongoDB<ic_item_stockoccupy> _ic_item_stockoccupy;
+
+        /// <summary>
+        /// 物料详情
+        /// </summary>
+        private readonly IMongoDB<ic_item> _ic_item;
+        private IRepository<ic_item, long> _mysql_ic_item;
+
+        /// <summary>
+        /// 物料BOM
+        /// </summary>
+        private readonly IMongoDB<ic_bom> _ic_bom;
+        private IRepository<ic_bom, long> _mysql_ic_bom;
+        /// <summary>
+        /// 物料BOM明细
+        /// </summary>
+        private readonly IMongoDB<ic_bom_child> _ic_bom_child;
+        private IRepository<ic_bom_child, long> _mysql_ic_bom_child;
+
+        /// <summary>
+        /// 物料库存表
+        /// </summary>
+        private readonly IMongoDB<ic_item_stock> _ic_item_stock;
+        private IRepository<ic_item_stock, long> _mysql_ic_item_stock;
+
+        /// <summary>
+        /// 物料采购计划表
+        /// </summary>
+        private readonly IMongoDB<ic_plan> _ic_plan;
+        private IRepository<ic_plan, long> _mysql_ic_plan;
+
+        /// <summary>
+        /// 物料工厂明细表
+        /// </summary>
+        private readonly IMongoDB<ic_factory_details> _ic_factory_details;
+        private IRepository<ic_factory_details, long> _mysql_ic_factory_details;
+
+        /// <summary>
+        /// 物料采购报价单
+        /// </summary>
+        private readonly IMongoDB<ic_item_pur> _ic_item_pur;
+        private IRepository<ic_item_pur, long> _mysql_ic_item_pur;
+
+        /// <summary>
+        /// 采购申请单
+        /// </summary>
+        private readonly IMongoDB<srm_pr_main> _srm_pr_main;
+        private IRepository<srm_pr_main, long> _mysql_srm_pr_main;
+
+        /// <summary>
+        /// 采购订单表
+        /// </summary>
+        private readonly IMongoDB<srm_po_main> _srm_po_main;
+        private IRepository<srm_po_main, long> _mysql_srm_po_main;
+
+        /// <summary>
+        /// 采购订单明细表
+        /// </summary>
+        private readonly IMongoDB<srm_po_list> _srm_po_list;
+        private IRepository<srm_po_list, long> _mysql_srm_po_list;
+
+        /// <summary>
+        /// 采购订单占用详情
+        /// </summary>
+        private readonly IMongoDB<srm_po_occupy> _srm_po_occupy;
+        private IRepository<srm_po_occupy, long> _mysql_srm_po_occupy;
+
+        /// <summary>
+        /// 委外工单
+        /// </summary>
+        private readonly IMongoDB<mes_oorder> _mes_oorder;
+        private IRepository<mes_oorder, long> _mysql_mes_oorder;
+
+        /// <summary>
+        /// 物料质检表
+        /// </summary>
+        private readonly IMongoDB<ic_check> _ic_check;
+        /// <summary>
+        /// 替代群组
+        /// </summary>
+        private readonly IMongoDB<ic_substitute> _ic_substitute;
+        /// <summary>
+        /// 替代群组
+        /// </summary>
+        private readonly IMongoDB<ic_substitute_all> _ic_substitute_all;
+        /// <summary>
+        /// 替代群组
+        /// </summary>
+        private readonly IMongoDB<ic_substitute_all_dtl> _ic_substitute_all_dtl;
+
+        /// <summary>
+        /// 生产工单主表
+        /// </summary>
+        private readonly IMongoDB<mes_morder> _mes_morder;
+        /// <summary>
+        /// 生产工单子表
+        /// </summary>
+        private readonly IMongoDB<mes_moentry> _mes_moentry;
+
+        /// <summary>
+        /// 在制工单占用记录表
+        /// </summary>
+        private readonly IMongoDB<mes_mooccupy> _mes_mooccupy;
+        /// <summary>
+        /// mysql在制工单占用表
+        /// </summary>
+        private readonly IRepository<mes_mooccupy, long> _mysql_mes_mooccupy;
+        /// <summary>
+        /// 销售订单
+        /// </summary>
+        private readonly IRepository<crm_seorder, long> _mysql_crm_seorder;
+        /// <summary>
+        /// 销售订单明细
+        /// </summary>
+        private readonly IRepository<crm_seorderentry, long> _mysql_crm_seorderentry;
+
+        /// <summary>
+        /// 生产工单主表
+        /// </summary>
+        private readonly IRepository<mes_morder, long> _mysql_mes_morder;
+        /// <summary>
+        /// 生产工单子表
+        /// </summary>
+        private readonly IRepository<mes_moentry, long> _mysql_mes_moentry;
+
+        /// <summary>
+        /// 资源检查入参
+        /// </summary>
+        private readonly SeorderentryDto param = new SeorderentryDto();
+
+        /// <summary>
+        /// 产能检查
+        /// </summary>
+        private readonly ProductExamineAppService _productExamineAppService;
+        /// <summary>
+        /// 工单App
+        /// </summary>
+        private readonly MorderAppService _morderAppService;
+
+        private List<ICItemLeadTimeDto> leadTimeList;
+
+        private List<ic_item_pur> supplierList;
+
+        private List<ic_plan> planList;
+
+        private List<SRMPRDto> SRMPRDtoList = new List<SRMPRDto>();
+
+        private List<mes_oorder> orderList = new List<mes_oorder>();
+        #endregion
+
+        #region 构造函数
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="icitem"></param>
+        /// <param name="icbom"></param>
+        public ResourceExamineAppService(
+            IMongoDB<ic_item> ic_item,
+            IMongoDB<ic_bom> ic_bom,
+            IMongoDB<ic_bom_child> ic_bom_child,
+            IMongoDB<ic_item_stock> ic_item_stock,
+            IMongoDB<ic_check> ic_check,
+            IMongoDB<ic_factory_details> ic_factory_details,
+            IMongoDB<mes_oorder> mes_oorder,
+            IMongoDB<srm_pr_main> srm_pr_main,
+            IMongoDB<srm_po_main> srm_po_main,
+            IMongoDB<srm_po_list> srm_po_list,
+            IMongoDB<srm_po_occupy> srm_po_occupy,
+            IMongoDB<ic_item_pur> ic_item_pur,
+            IMongoDB<ic_plan> ic_plan,
+            IMongoDB<ic_substitute> ic_substitute,
+            IMongoDB<ic_substitute_all> ic_substitute_all,
+            IMongoDB<ic_substitute_all_dtl> ic_substitute_all_dtl,
+            IMongoDB<mes_morder> mes_morder,
+            IMongoDB<mes_moentry> mes_moentry,
+            IMongoDB<mes_mooccupy> mes_mooccupy,
+            IMongoDB<ic_item_stockoccupy> ic_item_stockoccupy,
+            IRepository<ic_item, long> mysql_ic_item,
+            IRepository<ic_bom, long> mysql_ic_bom,
+            IRepository<ic_bom_child, long> mysql_ic_bom_child,
+            IRepository<mes_technique, long> mysql_mes_technique,
+            IRepository<crm_seorder, long> mysql_crm_seorder,
+            IRepository<crm_seorderentry, long> mysql_crm_seorderentry,
+            IRepository<ic_item_stock, long> mysql_ic_item_stock,
+            IRepository<ic_factory_details, long> mysql_ic_factory_details,
+            IRepository<mes_oorder, long> mysql_mes_oorder,
+            IRepository<srm_pr_main, long> mysql_srm_pr_main,
+            IRepository<mes_mooccupy, long> mysql_mes_mooccupy,
+            IRepository<mes_morder, long> mysql_mes_morder,
+            IRepository<mes_moentry, long> mysql_mes_moentry,
+            IRepository<mes_process, long> mysql_mes_process,
+            IRepository<mes_tech_process, long> mysql_mes_tech_process,
+            IRepository<srm_po_main, long> mysql_srm_po_main,
+            IRepository<srm_po_list, long> mysql_srm_po_list,
+            IRepository<srm_po_occupy, long> mysql_srm_po_occupy,
+            IRepository<ic_item_pur, long> mysql_ic_item_pur,
+            IRepository<ic_plan, long> mysql_ic_plan,
+            ProductExamineAppService productExamineAppService,
+            MorderAppService morderAppService
+            )
+        {
+            _ic_item = ic_item;
+            _ic_bom = ic_bom;
+            _ic_bom_child = ic_bom_child;
+            _ic_item_stock = ic_item_stock;
+            _ic_check = ic_check;
+            _ic_factory_details = ic_factory_details;
+            _mes_oorder = mes_oorder;
+            _srm_pr_main = srm_pr_main;
+            _srm_po_main = srm_po_main;
+            _srm_po_list = srm_po_list;
+            _srm_po_occupy = srm_po_occupy;
+            _ic_item_pur = ic_item_pur;
+            _ic_plan = ic_plan;
+            _ic_substitute = ic_substitute;
+            _ic_substitute_all = ic_substitute_all;
+            _ic_substitute_all_dtl = ic_substitute_all_dtl;
+            _mes_morder = mes_morder;
+            _mes_moentry = mes_moentry;
+            _mes_mooccupy = mes_mooccupy;
+            _ic_item_stockoccupy = ic_item_stockoccupy;
+            _mysql_ic_item = mysql_ic_item;
+            _mysql_ic_bom = mysql_ic_bom;
+            _mysql_ic_bom_child = mysql_ic_bom_child;
+            _mysql_crm_seorder = mysql_crm_seorder;
+            _mysql_crm_seorderentry = mysql_crm_seorderentry;
+            _mysql_ic_item_stock = mysql_ic_item_stock;
+            _mysql_ic_factory_details = mysql_ic_factory_details;
+            _mysql_mes_oorder = mysql_mes_oorder;
+            _mysql_srm_pr_main = mysql_srm_pr_main;
+            _mysql_mes_mooccupy = mysql_mes_mooccupy;
+            _mysql_mes_morder = mysql_mes_morder;
+            _mysql_mes_moentry = mysql_mes_moentry;
+            _mysql_srm_po_main = mysql_srm_po_main;
+            _mysql_srm_po_list = mysql_srm_po_list;
+            _mysql_srm_po_occupy = mysql_srm_po_occupy;
+            _mysql_ic_item_pur = mysql_ic_item_pur;
+            _mysql_ic_plan = mysql_ic_plan;
+            _productExamineAppService = productExamineAppService;
+            _morderAppService = morderAppService;
+        }
+        #endregion
+
+        /// <summary>
+        /// 资源检查
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        public async Task<string> ReceiveResult(SeorderentryDto input)
+        {
+            //资源检查入参全局变量赋值
+            param.sorderId = input.sorderId;
+            param.tenantId = input.tenantId;
+            param.factoryId = input.factoryId;
+
+            //资源检查结果
+            PschedDto rtn = new PschedDto();
+            rtn.sorderid = input.sorderId;
+            //资源检查明细list
+            List<ExamineResult> examines = new List<ExamineResult>();
+            ExamineResult dtl;
+
+            //生成当前计算bangid
+            SnowFlake snow = new SnowFlake();
+            long bangid = snow.NextId();
+
+            //获取订单数据
+            crm_seorder sorder = _mysql_crm_seorder.GetListAsync(p => p.tenant_id == input.tenantId && p.factory_id == input.factoryId && p.Id == input.sorderId && !p.IsDeleted).Result.FirstOrDefault();
+            if (sorder == null)
+            {
+                throw new NotImplementedException("订单数据不存在!");
+            }
+            //获取订单行数据
+            List<crm_seorderentry> sentrys = await _mysql_crm_seorderentry.GetListAsync(p => p.tenant_id == input.tenantId && p.factory_id == input.factoryId && p.seorder_id == input.sorderId && !p.IsDeleted);
+
+            //数据库快照-同步mysql库数据到mongoDB中
+            //await SyncData(input.tenantId, input.factoryId, bangid);
+
+            //通过订单行的产品代码获取物料BOM数据
+            //FilterDefinition<ic_bom> filter = Builders<ic_bom>.Filter.In(s => s.bom_number, sentrys.Select(m => m.bom_number).ToList());
+            //List<ic_bom> boms = _ic_bom.GetManyByIds(filter).Result.Where(p => p.factory_id == input.factoryId && p.tenant_id == input.tenantId && !p.IsDeleted).ToList();
+            List<ic_bom> boms = _ic_bom.Find(p => sentrys.Select(m => m.item_number).Contains(p.item_number) && p.factory_id == input.factoryId && p.tenant_id == input.tenantId && !p.IsDeleted).Result.ToList();
+
+            //物料bom
+            List<ic_bom> bomlist = new List<ic_bom>();
+            //物料bom明细
+            List<ic_bom_child> bomchildlist = new List<ic_bom_child>();
+            //获取物料bom,物料bom明细
+            GetIcBomData(boms, bomlist, bomchildlist);
+
+            //根据明细集合查出所有得替代关系表数据集合
+            List<string> codeList = bomchildlist.Select(c => c.substitute_code).ToList();
+            var sublist = _ic_substitute.GetManyByCondition(p => codeList.Contains(p.substitute_code) && !p.IsDeleted).Result;
+
+            List<long> subidlist = sublist.Select(c => c.Id).ToList();
+            var suballlist = _ic_substitute_all.GetManyByCondition(p => subidlist.Contains(p.substitute_id) && !p.IsDeleted).Result;
+
+            List<long> suballidlist = suballlist.Select(c => c.Id).ToList();
+            var subdtllist = _ic_substitute_all_dtl.GetManyByCondition(p => suballidlist.Contains(p.substitute_allid) && !p.IsDeleted).Result;
+
+
+
+            //物料占用记录
+            List<ic_item_stockoccupy> sklist = new List<ic_item_stockoccupy>();
+            //获取物料数据
+            List<long> itemIds = bomlist.Select(p => p.icitem_id).ToList();
+            itemIds.AddRange(bomchildlist.Select(p => p.icitem_id).ToList());
+            itemIds.AddRange(subdtllist.Select(p => p.icitem_id).ToList());
+            List<ic_item> icitemlist = _ic_item.GetManyByCondition(p => itemIds.Contains(p.Id) && !p.IsDeleted).Result;
+
+            //物料提前期
+            leadTimeList = GetLeadTime(itemIds, input.tenantId, input.factoryId);//提前期列表
+            supplierList = GetSupplier(itemIds, input.tenantId, input.factoryId);//供应商列表
+            planList = GetICPlan(itemIds, input.tenantId, input.factoryId);//plan列表
+
+            foreach (var item in sentrys)
+            {
+                //工单资源检查信息
+                dtl = new ExamineResult();
+                dtl.sentry_id = item.Id;
+                //TODO:最早开始时间默认3天后(后期调整)
+                dtl.earliest_times = DateTime.Now.Date.AddDays(3);
+
+                //获取当前物料bom数据
+                var childBom = boms.Where(p => p.item_number == item.item_number).FirstOrDefault();
+                //bom层级组装
+                var getBomList = BomPretreatment(childBom.Id, bomlist, bomchildlist, icitemlist);
+                //bom替代关系组装
+                BomSubstitute(getBomList, bomlist, bomchildlist, icitemlist, sublist, suballlist, subdtllist);
+                //库存初始化
+                BomStock(getBomList);
+                //计算
+                calcTest(getBomList, bangid, item.Id, item.qty.Value, input, item.plan_date, sklist, item, icitemlist);
+
+                //TODO:最晚开始时间
+                var curFacDtl = leadTimeList.FirstOrDefault(p => p.item_id == childBom.icitem_id);
+                //最晚开工时间=订单行客户要求交期-运输提前期-库存提前期-生产提前期-下单提前期
+                dtl.latest_times = item.plan_date.GetValueOrDefault().AddDays(-Convert.ToDouble(curFacDtl?.transportation_leadtime.GetValueOrDefault() + curFacDtl?.stock_leadtime.GetValueOrDefault() + curFacDtl?.production_leadtime.GetValueOrDefault() + curFacDtl?.order_leadtime.GetValueOrDefault()));
+                //物料齐套时间
+                dtl.kitting_times = getBomList.Where(p => p.is_use).OrderByDescending(m => m.kitting_time).First().kitting_time.GetValueOrDefault();
+                //替代关系展开list
+                dtl.substitutes = getBomList;
+                //添加订单行开工信息
+                examines.Add(dtl);
+                //生成工单 TODO:0=产品数量
+                //GenerateMorder(o, 0);
+            }
+            //订单行资源检查明细list
+            rtn.srm_pr_list = SRMPRDtoList;
+            rtn.order_list = orderList;
+            rtn.examines = examines;
+            rtn.sklist = sklist;
+            return JsonConvert.SerializeObject(rtn);
+        }
+
+        /// <summary>
+        /// 递归:获取icbom,icbomchild数据
+        /// </summary>
+        /// <param name="icBoms"></param>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        public void GetIcBomData(List<ic_bom> icBoms, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist)
+        {
+            if (icBoms.Count() == 0)
+            {
+                return;
+            }
+            //添加物料bom数据
+            bomlist.AddRange(icBoms);
+            //获取物料bom明细数据
+            List<ic_bom_child> childList = _ic_bom_child.GetManyByCondition(p => icBoms.Select(m => m.Id).Contains(p.bom_id) && p.use_status == 1 && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted).Result.ToList();
+            //没有明细数据,终止
+            if (childList.Count == 0)
+            {
+                return;
+            }
+            bomchildlist.AddRange(childList);
+            //通过物料bom明细数据反查物料bom数据
+            var boms = _ic_bom.GetManyByCondition(p => childList.Select(m => m.icitem_id).ToList().Contains(p.icitem_id) && p.fse_status == 1 && p.tenant_id == param.tenantId && p.factory_id == param.factoryId && !p.IsDeleted).Result.ToList();
+            foreach (var chd in childList)
+            {
+                var curBoms = boms.Where(p => p.icitem_id == chd.icitem_id).ToList();
+                GetIcBomData(curBoms, bomlist, bomchildlist);
+            }
+        }
+
+        /// <summary>
+        /// 数据库快照
+        /// </summary>
+        /// <returns></returns>
+        public async Task SyncData(long tenantId, long factoryId, long bangid)
+        {
+            //同步物料库存数据
+            var icitemStokc = _mysql_ic_item_stock.GetListAsync(p => p.tenant_id == tenantId && p.factory_id == factoryId).Result;
+            if (icitemStokc.Count > 0)
+            {
+                //设置当前计算bangid
+                icitemStokc.ForEach(item => { item.bang_id = bangid; });
+                //插入数据
+                await _ic_item_stock.InsertMany(icitemStokc);
+            }
+            //在制工单占用记录表
+            var mes_mooccupy = _mysql_mes_mooccupy.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (mes_mooccupy.Count > 0)
+            {
+                mes_mooccupy.ForEach(item => { item.bang_id = bangid; });
+                await _mes_mooccupy.InsertMany(mes_mooccupy);
+            }
+            //工单主表
+            var mes_morder = _mysql_mes_morder.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (mes_morder.Count > 0)
+            {
+                mes_morder.ForEach(item => { item.bang_id = bangid; });
+                await _mes_morder.InsertMany(mes_morder);
+            }
+            //工单子表
+            var mes_moentry = _mysql_mes_moentry.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (mes_moentry.Count > 0)
+            {
+                mes_moentry.ForEach(item => { item.bang_id = bangid; });
+                await _mes_moentry.InsertMany(mes_moentry);
+            }
+
+            //TODO:要不要根据某些条件只同步有效的数据
+            //销售订单
+            //var crm_seorder = _mysql_crm_seorder.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            //if (crm_seorder.Count > 0)
+            //{
+            //    crm_seorder.ForEach(item => { item.bang_id = bangid; });
+            //    await _crm_seorder.InsertMany(crm_seorder);
+            //}
+
+            ////销售订单明细
+            //var crm_seorderentry = _mysql_crm_seorderentry.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            //if (crm_seorderentry.Count > 0)
+            //{
+            //    crm_seorderentry.ForEach(item => { item.bang_id = bangid; });
+            //    await _crm_seorderentry.InsertMany(crm_seorderentry);
+            //}
+
+            //采购订单
+            var srm_po_main = _mysql_srm_po_main.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (srm_po_main.Count > 0)
+            {
+                srm_po_main.ForEach(item => { item.bang_id = bangid; });
+                await _srm_po_main.InsertMany(srm_po_main);
+            }
+
+            //采购订单明细
+            var srm_po_list = _mysql_srm_po_list.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (srm_po_list.Count > 0)
+            {
+                srm_po_list.ForEach(item => { item.bang_id = bangid; });
+                await _srm_po_list.InsertMany(srm_po_list);
+            }
+
+            //采购订单占用详情
+            var srm_po_occupy = _mysql_srm_po_occupy.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (srm_po_occupy.Count > 0)
+            {
+                srm_po_occupy.ForEach(item => { item.bang_id = bangid; });
+                await _srm_po_occupy.InsertMany(srm_po_occupy);
+            }
+
+            //工厂物料明细表
+            var ic_factory_details = _mysql_ic_factory_details.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (ic_factory_details.Count > 0)
+            {
+                ic_factory_details.ForEach(item => { item.bang_id = bangid; });
+                await _ic_factory_details.InsertMany(ic_factory_details);
+            }
+
+            //物料采购计划表
+            var ic_plan = _mysql_ic_plan.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (ic_plan.Count > 0)
+            {
+                ic_plan.ForEach(item => { item.bang_id = bangid; });
+                await _ic_plan.InsertMany(ic_plan);
+            }
+
+            //物料采购报价单
+            var ic_item_pur = _mysql_ic_item_pur.GetListAsync(x => x.tenant_id == tenantId && x.factory_id == factoryId).Result;
+            if (ic_item_pur.Count > 0)
+            {
+                ic_item_pur.ForEach(item => { item.bang_id = bangid; });
+                await _ic_item_pur.InsertMany(ic_item_pur);
+            }
+        }
+
+        /// <summary>
+        /// BOM预处理
+        /// </summary>
+        /// <param name="orderid"></param>
+        /// <param name="BomId"></param>
+        /// <param name="Quantity"></param>
+        public List<BomChildExamineDto> BomPretreatment(long? BomId, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist)
+        {
+            if (BomId == null)
+            {
+                //throw new bu
+            }
+            List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+
+            var bom = bomlist.Find(s => s.Id == BomId);
+            if (bom == null)
+            {
+                return returnlist;
+            }
+
+            var dto = new BomChildExamineDto();
+            dto.item_id = bom.icitem_id;
+            dto.bom_id = BomId.Value;
+            dto.bom_number = bom.bom_number;
+            dto.level = 1;
+            dto.id = help.NextId();
+            dto.parent_id = help.NextId();
+            dto.qty = 1;
+            dto.num = "1";
+            dto.isbom = 1;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            int type = 0;
+            GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            return returnlist;
+        }
+
+        /// <summary>
+        /// BOM预处理层级组装
+        /// </summary>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="dto"></param>
+        /// <param name="returnlist"></param>
+        public void GetBomList(List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, BomChildExamineDto dto, List<BomChildExamineDto> returnlist, int type)
+        {
+            int level = dto.level + 1;//初始化定义level层级
+
+            var bom = bomlist.Where(s => s.Id == dto.bom_id).FirstOrDefault();
+            ic_item item = new ic_item();
+            if (bom != null)
+            {
+                item = icitemlist.Where(a => a.Id == bom.icitem_id).FirstOrDefault();
+            }
+            else
+            {
+                item = icitemlist.Where(a => a.Id == dto.item_id).FirstOrDefault();
+            }
+            if (item == null)
+            {
+                return;
+            }
+            dto.item_id = item.Id;
+            dto.item_name = bom.item_name;
+            dto.item_code = bom.item_number;
+            dto.model = item.model;
+            dto.unit = bom.unit;
+            dto.erp_cls = item.erp_cls;
+            dto.erp_cls_name = item.erp_cls_name;
+            dto.type = type;
+            dto.item_number = item.number;
+
+            //var bdto = ObjectMapper.Map<ic_bom,BomChildExamineDto>(bom);
+            returnlist.Add(dto);
+            var childlist = bomchildlist.Where(a => a.bom_id == bom.Id).ToList();
+
+            int idx = 1;
+            foreach (var c in childlist)
+            {
+                string childNum = dto.num + "." + idx.ToString();
+                var icitem = icitemlist.Where(a => a.Id == c.icitem_id).FirstOrDefault();
+                var childBom = bomlist.Where(a => a.icitem_id == c.icitem_id).FirstOrDefault();
+                //如果此明细查的到BOM信息,则代表此child是一个子BOM。
+                if (childBom != null)
+                {
+                    var cdto = new BomChildExamineDto();
+                    cdto.id = help.NextId();
+                    cdto.level = level;
+                    cdto.parent_id = dto.id;
+                    cdto.bom_child_id = c.Id;
+                    cdto.qty = c.qty.Value;
+                    cdto.backflush = c.backflush;
+                    cdto.num = childNum;
+                    cdto.isbom = 1;
+                    cdto.is_replace = c.is_replace;
+                    cdto.haveicsubs = c.haveicsubs;
+                    cdto.substitute_code = c.substitute_code;
+                    cdto.icitem_ids = c.icitem_ids;
+                    cdto.type = type;
+                    cdto.item_id = childBom.icitem_id;
+                    cdto.bom_id = childBom.Id;
+                    cdto.bom_number = childBom.bom_number;
+                    //递归寻找子级
+                    GetBomList(bomlist, bomchildlist, icitemlist, cdto, returnlist, type);
+                }
+                else
+                {
+                    if (icitem != null)
+                    {
+                        var childDto = new BomChildExamineDto();
+                        childDto.level = level;
+                        childDto.bom_id = dto.bom_id;
+                        childDto.bom_child_id = c.Id;
+                        childDto.id = help.NextId();
+                        childDto.parent_id = dto.id;
+                        childDto.item_id = icitem.Id;
+                        childDto.item_name = icitem.name;
+                        childDto.item_code = icitem.number;
+                        childDto.num = childNum;
+                        childDto.model = icitem.model;
+                        childDto.unit = c.unit;
+                        childDto.erp_cls = icitem.erp_cls;
+                        childDto.erp_cls_name = icitem.erp_cls_name;
+                        childDto.backflush = c.backflush;
+                        childDto.qty = c.qty.Value;
+                        childDto.isbom = 0;
+                        childDto.is_replace = c.is_replace;
+                        childDto.haveicsubs = c.haveicsubs;
+                        childDto.substitute_code = c.substitute_code;
+                        childDto.icitem_ids = c.icitem_ids;
+                        childDto.type = type;
+                        childDto.item_number = icitem.number;
+                        returnlist.Add(childDto);
+                    }
+                }
+                idx++;
+            }
+
+        }
+
+
+        /// <summary>
+        /// BOM替代关系预处理
+        /// </summary>
+        public void BomSubstitute(List<BomChildExamineDto> returnlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, List<ic_substitute> sublist, List<ic_substitute_all> suballlist, List<ic_substitute_all_dtl> subdtllist)
+        {
+            List<long> childidList = new List<long>();
+            int type = 1;
+            List<BomChildExamineDto> addlist = new List<BomChildExamineDto>();
+
+            //除顶级外,其他层级关系全带出来。生成平铺
+            foreach (var item in returnlist)
+            {
+                //最顶级、虚拟件
+                if (item.level == 1 || item.erp_cls == 4 || childidList.Contains(item.bom_child_id.GetValueOrDefault()))
+                {
+                    continue;
+                }
+                //有替代关系
+                if (item.haveicsubs != 1)
+                {
+                    continue;
+                }
+                if (!string.IsNullOrEmpty(item.icitem_ids))
+                {
+                    long cid = 1;
+                    var cids = item.icitem_ids.Split(',');
+                    foreach (var c in cids)
+                    {
+                        if (long.TryParse(c, out cid))
+                        {
+                            childidList.Add(cid);
+                        }
+                    }
+                }
+
+
+                //找到当前物料的替代群组关系集
+                var sl = sublist.Find(s => s.substitute_code == item.substitute_code);
+                if (sl != null)
+                {
+                    var sall = suballlist.Where(s => s.substitute_id == sl.Id).ToList();
+                    foreach (var sal in sall)
+                    {
+                        var sadl = subdtllist.Where(s => s.substitute_allid == sal.Id).ToList();
+                        foreach (var dtl in sadl)
+                        {
+                            if (sal.main_material.GetValueOrDefault() != 1)
+                            {
+                                //递归将替代关系组装出来。
+                                SubstitutePretreatment(sl, sal, dtl, item, addlist, icitemlist, bomlist, bomchildlist, type);
+                            }
+                            else
+                            {
+                                //将主料赋值上属性
+                                var dtlitem = returnlist.Find(s => s.item_id == dtl.icitem_id && s.level == item.level);
+                                dtlitem.substitute_all_num = sal.order_num;//群组优先级
+                            }
+                        }
+
+
+
+                    }
+                }
+            }
+            returnlist.AddRange(addlist);
+        }
+
+        /// <summary>
+        /// 替代关系递归组装出来
+        /// </summary>
+        /// <param name="sal"></param>
+        /// <param name="dtl"></param>
+        /// <param name="toDto"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        public void SubstitutePretreatment(ic_substitute sl, ic_substitute_all sal, ic_substitute_all_dtl dtl, BomChildExamineDto toDto, List<BomChildExamineDto> returnlist, List<ic_item> icitemlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, int type)
+        {
+            //如果dtl对应的icitem是BOM,还需要向下继续展开。
+
+            //List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+            var dto = new BomChildExamineDto();
+            var bom = bomlist.Where(s => s.icitem_id == dtl.icitem_id).FirstOrDefault();
+            var icitem = icitemlist.Find(s => s.Id == dtl.icitem_id);
+            if (icitem == null)
+            {
+                return;
+            }
+            dto.id = help.NextId();
+            dto.level = toDto.level;
+            dto.parent_id = toDto.parent_id;
+            dto.item_id = icitem.Id;
+            dto.item_name = icitem.name;
+            dto.item_code = icitem.number;
+            dto.num = toDto.num;
+            dto.model = icitem.model;
+            dto.unit = icitem.unit;
+            dto.erp_cls = icitem.erp_cls;
+            dto.erp_cls_name = icitem.erp_cls_name;
+            dto.backflush = toDto.backflush;
+            //dto.qty = toDto.qty;
+            //dto.replace_amount = dtl.replace_amount.Value;
+            dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            dto.substitute_strategy = sl.substitute_strategy == null ? 0 : sl.substitute_strategy.Value;//替代策略
+            dto.substitute_mode = sl.substitute_mode == null ? 0 : sl.substitute_mode.Value;//替代方式
+            dto.type = type;
+            dto.substitute_all_num = sal.order_num;//群组优先级
+            if (bom != null)
+            {
+                dto.bom_id = bom.Id;
+
+                dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+                dto.isbom = 1;
+                dto.is_replace = 0;
+                dto.haveicsubs = 0;
+                dto.substitute_code = "";
+                dto.icitem_ids = "";
+                GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            }
+            else
+            {
+                dto.bom_id = null;
+                dto.isbom = 0;
+                returnlist.Add(dto);
+            }
+        }
+
+        /// <summary>
+        /// 计算物料库存量
+        /// </summary>
+        /// <param name="returnlist"></param>
+        public void BomStock(List<BomChildExamineDto> returnlist)
+        {
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
+            //获取当前工厂下物料库存数据
+            List<long> icitemIds = returnlist.Select(c => c.item_id).ToList();
+            var stocklist = _ic_item_stock.GetManyByCondition(p => p.factory_id == param.factoryId && icitemIds.Contains(p.icitem_id)).Result;
+            //计算剩余库存
+            foreach (var item in returnlist)
+            {
+                if (item.erp_cls == 4)//虚拟件不计算
+                {
+                    continue;
+                }
+                //非虚拟件
+                //当前物料的库存数量
+                decimal stockQty = stocklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.sqty.GetValueOrDefault());
+                //获取当前订单其他订单行当前物料的占用数量
+                //decimal otherStockQty = occupylist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
+                //当前订单行物料库存情况
+                //item.sqty = stockQty - otherStockQty;
+                item.sqty = stockQty;
+            }
+        }
+
+        /// <summary>
+        /// 替代关系计算
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="orderid"></param>
+        /// <param name="count"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid, decimal count, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item_stockoccupy> sklist, crm_seorderentry sentrys,List<ic_item> icitemlist)
+        {
+            //第一级
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
+            var childList = returnlist.Where(s => s.parent_id == returnlist[0].id && s.type == 0).OrderBy(s => s.num).ToList();
+
+            var planList = GetICPlan(returnlist.Select(p => p.item_id).ToList(), bangid, param.factoryId);//plan列表
+
+            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
+            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
+            List<long> calcIds = new List<long>();
+            //先处理下最顶级的产品需要数量
+            returnlist[0].needCount = returnlist[0].qty * count;
+            returnlist[0].lack_qty = returnlist[0].needCount - returnlist[0].sqty;
+
+            foreach (var item in returnlist)
+            {
+                if (item.level == 1)
+                {
+                    continue;
+                }
+                //循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
+                CaclMaterialShortage(returnlist, item, count);
+            }
+            Mes_MorderDto mes_MorderDto = new Mes_MorderDto();
+            if (returnlist[0].lack_qty > 0)
+            {
+                //获取物料详情
+                var ic_item = icitemlist.Find(s => s.Id == returnlist[0].item_id);
+                var mooccupylist = _morderAppService.CheckMorder(returnlist[0].bom_number, returnlist[0].lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                returnlist[0].mo_qty = moo_qty;
+                if (moo_qty == returnlist[0].lack_qty)
+                {
+                    //在制完全足够
+                    returnlist[0].lack_qty = 0;
+                    returnlist[0].satisfy_time = mooccupylist[0].moo_etime;
+                    returnlist[0].stock_state = 1;
+                    return;
+                }
+                else
+                {
+                    //占用不够,占用后减少缺料数量
+                    returnlist[0].lack_qty -= moo_qty;
+                    //先设定在制的齐套时间
+                    returnlist[0].satisfy_time = mooccupylist[0]?.moo_etime;
+                    returnlist[0].stock_state = 0;
+                    //生成主工单
+                    GenerateMorderDto generateMorderDto = new GenerateMorderDto()
+                    {
+                        seorderentry = sentrys,
+                        ic_Item = ic_item,
+                        BomNumber = returnlist[0].bom_number,
+                        version = returnlist[0].version,
+                        number = returnlist[0].item_number,
+                        Quantity = returnlist[0].lack_qty,
+                        morder_type = "销售工单",
+                        work_order_type = "常规工单",
+                        morder_state = "初始",
+
+                    };
+                    //生成主工单
+                    mes_MorderDto = _morderAppService.GenerateMorder(generateMorderDto);
+                }
+            }
+            else {
+                returnlist[0].satisfy_time = DateTime.Now;
+                returnlist[0].stock_state = 1;
+                return;
+            }
+
+            //这是从上往下展开计算缺料和可制
+            calcTest2(returnlist[0], childList, returnlist, sklist);
+            //returnlist[0].kz = childList.Min(s => s.kz);//得到最小可制数量。
+            //再加个循环,来根据替代关系里的检查结果,根据规则明确使用和生成占用关系。
+            CalcIcitem(childList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+            returnlist[0].kitting_time = childList.Max(s => s.kitting_time);
+            //这里更新产品得满足时间。
+            if (mes_MorderDto != null)
+            {
+                //主工单最后计算满足日期
+                var mes_Morders = mes_MorderDto.mes_Morders.Where(x => x.parent_id == null).FirstOrDefault();
+                if (mes_Morders != null)
+                {
+                    if (!string.IsNullOrEmpty(mes_Morders.bom_number))
+                    {
+                        //var ProductiveDate = ProductiveExamine(mes_Morders.bom_number, returnlist[0].version, (int)mes_Morders.morder_production_number.Value);
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = mes_Morders.bom_number,
+                            version = returnlist[0].version,
+                            packages = (int)mes_Morders.morder_production_number.Value,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var plan = planList.Find(x => x.icitem_id == returnlist[0].item_id);
+                        var ProductiveDate = _productExamineAppService.ProductiveExamine(prodExamine);
+                        var Day = ProductiveDate.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        mes_Morders.moentry_sys_stime = returnlist[0].kitting_time.Value.AddDays(1);//数据齐套完成后隔天开始生产;
+                        //结束日期=开始时间+生产时长+自检提前期+入库提前期+发运提前期;
+                        var LeadTime = Day + plan.self_inspection_date.Value + plan.Shipping_date.Value + plan.Warehousing_date.Value;
+                        mes_Morders.moentry_sys_etime = mes_Morders.moentry_sys_stime.Value.AddDays((double)Day);
+                        mes_Morders.morder_need_time = ProductiveDate.Result;
+                        //满足资源检查的时间需加上提前期
+                        returnlist[0].satisfy_time = mes_Morders.moentry_sys_stime.Value.AddDays((double)LeadTime);
+                    }
+                    //批量保存 后期考虑子工单
+                    _mes_morder.InsertMany(mes_MorderDto.mes_Morders);
+                    _mes_moentry.InsertMany(mes_MorderDto.mes_Moentries);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 循环计算物料情况
+        /// </summary>
+        /// <param name="childList"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="orderid"></param>
+        /// <param name="input"></param>
+        /// <param name="sklist"></param>
+        /// <param name="plan_date"></param>
+        public void CalcIcitem(List<BomChildExamineDto> childList, List<BomChildExamineDto> returnlist, long bangid, SeorderentryDto input, List<ic_item_stockoccupy> sklist, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            foreach (var item in childList)
+            {
+                var parent = returnlist.Find(s => s.id == item.parent_id);
+                if (parent.stock_state == 0)
+                {
+                    if (item.haveicsubs == 1)
+                    {
+                        //如果有替代关系,根据群组来明确使用哪个群组的替代料。按整批和混用逻辑来算
+                        // 如果有群组替代,就移除掉被检查过的记录 item.icitem_ids
+                        CalcStrategy(item, returnlist, bangid, sklist, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        Calczykc(item, parent, sklist);
+
+                        //直接占用库存,缺料就生成采购
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = item.item_id;
+                        itemStockoccupyDto.item_no = item.num;
+                        item.kitting_time = DateTime.Now;
+                        item.is_use = true;
+                        StartProcessing(item,icitemlist,returnlist,plan_date,sentrys,sklist,itemStockoccupyDto,bangid,input);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 针对缺料开始进行处理
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="plan_date"></param>
+        /// <param name="sentrys"></param>
+        /// <param name="sklist"></param>
+        /// <param name="itemStockoccupyDto"></param>
+        /// <param name="bangid"></param>
+        /// <param name="input"></param>
+        public void StartProcessing(BomChildExamineDto item, List<ic_item> icitemlist, List<BomChildExamineDto> returnlist, DateTime
+            ? plan_date, crm_seorderentry sentrys, List<ic_item_stockoccupy> sklist, ic_item_stockoccupy itemStockoccupyDto, long bangid, SeorderentryDto input)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            if (item.lack_qty > 0)
+            {
+                var cilList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).OrderBy(k => k.num).ToList();
+                //如果缺料,占用库存,然后走采购或自制
+                if (item.sqty > 0)
+                {
+                    itemStockoccupyDto.quantity = item.sqty;
+                    sklist.Add(itemStockoccupyDto);
+                }
+                item.use_qty = item.sqty;
+                if (item.erp_cls == 1)
+                {
+                    var ic_item = icitemlist.Find(s => s.Id == item.item_id);
+                    var mooccupylist = _morderAppService.CheckMorder(item.bom_number, item.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                    decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                    item.mo_qty = moo_qty;
+                    if (moo_qty == returnlist[0].lack_qty)
+                    {
+                        //在制完全足够
+                        item.lack_qty = 0;
+                        item.kitting_time = mooccupylist[0].moo_etime;
+                        item.stock_state = 1;
+                    }
+                    else
+                    {
+                        item.lack_qty -= moo_qty;
+                        item.kitting_time=DateTime.Now;
+                        //先计算末级数据的齐套时间。
+                        if (cilList.Count() > 0)
+                        {
+                            CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                            item.kitting_time = cilList.Max(s => s.kitting_time);
+                        }
+
+                        //走自制
+                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = item.bom_number,
+                            version = item.version,
+                            packages = (int)item.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        var ktime = item.kitting_time.Value.AddDays((double)Day);
+                        item.kitting_time = ktime > mooccupylist[0].moo_etime ? ktime : mooccupylist[0].moo_etime;
+                    }
+                }
+                else if (item.erp_cls == 3)
+                {
+                    //采购申请
+                    var SRMPRDto = CreateSRMPR(item, input.tenantId, input.factoryId, bangid, item.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                    item.kitting_time = SRMPRDto.lastStartTmie;
+                    SRMPRDtoList.Add(SRMPRDto);
+                }
+                else if (item.erp_cls == 2)
+                {
+                    //先计算末级数据的齐套时间。
+                    if (cilList.Count() > 0)
+                    {
+                        CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                        item.kitting_time = cilList.Max(s => s.kitting_time);
+                    }
+                    //1.先生成委外工单。
+                    var mesorder = CreateMesOOder(item, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                    item.kitting_time = mesorder.ooentry_etime;
+                    orderList.Add(mesorder);
+                }
+            }
+            else
+            {
+                //如果父级缺料,则本级等于父级缺料*本级使用数量
+                if (parent != null)
+                {
+                    item.use_qty = parent.lack_qty * item.qty;
+                    itemStockoccupyDto.quantity = item.use_qty;
+                }
+                sklist.Add(itemStockoccupyDto);
+            }
+        }
+
+
+        /// <summary>
+        /// 平铺计算物料情况
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="item"></param>
+        /// <param name="count"></param>
+        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item, decimal count)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            //当前物料总共需要数量
+            item.needCount = parent.needCount * item.qty;
+            /*//当前库存可以满足的数量
+            item.satisfyNum = item.sqty;
+            //总需要数量减去库存量,得出缺料数量
+            item.lack_qty = item.needCount - item.satisfyNum;
+            //如果不满足,计算子物料,或者计算替代料
+            if (item.lack_qty < 0)
+            {
+                //库存满足
+                item.stock_state = 1;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                item.stock_state = 0;
+            }*/
+        }
+
+        /// <summary>
+        /// 根据占用情况重新计算占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        public void RecalculationStock(BomChildExamineDto item, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist)
+        {
+            //再计算一边占用情况,这里根据父级产品额缺料量*当前子料的使用数量-子料库存量。得出当前子物料的缺料数量
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            decimal stockQty = sklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
+            item.sqty = item.sqty - stockQty;
+            item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+            item.lack_qty = item.lack_qty > 0 ? item.lack_qty : 0;
+            item.stock_state = item.lack_qty > 0 ? 0 : 1;
+        }
+
+        /// <summary>
+        /// 根据替代策略计算
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="sklist"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void CalcStrategy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, List<ic_item_stockoccupy> sklist, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            //提取群组关系
+            var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
+            List<BomChildExamineDto> select = new List<BomChildExamineDto>();
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            switch (item.substitute_strategy)
+            {
+                case 0://整批
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    //如果都需要采购的情况下,则默认使用优先级最高的
+                    WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 1://混用
+                    MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 2://整批加混用
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    if (select.Count() == 0)
+                    {
+                        //走混用
+                        MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        //走整批
+                        WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    break;
+            }
+        }
+        /// <summary>
+        /// 整批计算
+        /// </summary>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        public void WholeBatchCheck(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select)
+        {
+            for (int idx = 0; idx < 99; idx++)
+            {
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    //可制计算:需要对list进行可制计算,按主料来算辅料
+                    if (list.Where(s => s.stock_state != 1).Count() == 0)
+                    {
+                        //只满足充足或可制
+                        //无缺料情况
+                        select = list;
+                        select.ForEach(s => { s.is_use = true; });
+                        break;
+                    }
+                    idx++;
+                }
+                else
+                {
+                    idx = 99;
+                }
+            }
+        }
+        /// <summary>
+        /// 整批占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void WholeBatch(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            if (select.Count() == 0)
+            {
+                //如果为空,则默认使用优先级为0的集合作为替代关系
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                select.ForEach(s => { s.is_use = true; });
+            }
+            //占用库存
+            foreach (var slt in select)
+            {
+                ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                itemStockoccupyDto.bang_id = bangid;
+                itemStockoccupyDto.icitem_id = slt.item_id;
+                itemStockoccupyDto.item_no = slt.num;
+                slt.is_use = true;
+                StartProcessing(slt, icitemlist, returnlist, plan_date, sentrys, sklist, itemStockoccupyDto, bangid, input);
+            }
+
+        }
+
+        /// <summary>
+        /// 混用占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void MixedUse(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+
+            decimal parent_lack = 0;
+            if (parent != null)
+            {
+                parent_lack = parent.lack_qty;
+            }
+            for (int idx = 0; idx < 99; idx++)
+            {
+                if (parent_lack <= 0)
+                {
+                    break;
+                }
+
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    decimal minMake = 99999999;
+                    foreach (var hy in list)
+                    {
+                        //混用先使用掉当前要用的数量
+                        //得到库存最小数量,去占用,然后剩余的丢第二个循环里去占用。
+                        //获取物料详情
+                        var ic_item = icitemlist.Find(s => s.Id == hy.item_id);
+                        var mooccupylist = _morderAppService.CheckMorder(hy.bom_number, hy.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item, false).Result;
+                        decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                        decimal make = (hy.sqty + moo_qty) / hy.qty;
+                        if (Math.Floor(hy.qty) == hy.qty)
+                        {
+                            //如果物料的使用数量是小数,则按小数计算。
+                            make = Math.Floor(make);
+                        }
+                        if (minMake > make)
+                        {
+                            minMake = make;
+                        }
+                    }
+                    decimal use_p_num = 0;
+                    if (parent_lack > minMake) //20>10
+                    {
+                        use_p_num = minMake;
+                        parent_lack -= use_p_num;
+                    }
+                    else
+                    {
+                        use_p_num = parent_lack;
+                        parent_lack = 0;
+                    }
+                    //根据混用逻辑,去占用物料
+                    foreach (var zy in list)
+                    {
+                        zy.is_use = true;
+                        zy.kitting_time = DateTime.Now;
+                        if (parent_lack <= 0)
+                        {
+                            zy.stock_state = 1;
+                        }
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = zy.item_id;
+                        decimal moo_qty = use_p_num * zy.qty - zy.sqty;
+                        if (moo_qty > 0)
+                        {
+                            var ic_item = icitemlist.Find(s => s.Id == zy.item_id);
+                            var mooccupylist = _morderAppService.CheckMorder(zy.bom_number, moo_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                            itemStockoccupyDto.quantity = zy.sqty;
+                            zy.use_qty = zy.sqty;
+                            zy.mo_qty = moo_qty;
+                        }
+                        else {
+                            zy.use_qty = use_p_num * zy.qty;
+                            itemStockoccupyDto.quantity = zy.use_qty;
+                        }
+                        itemStockoccupyDto.item_no = zy.num;
+                        sklist.Add(itemStockoccupyDto);
+                    }
+                    idx++;
+                }
+            }
+            if (parent_lack > 0)
+            {
+                var select = new List<BomChildExamineDto>();
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                //对select执行采购
+                foreach (var sct in select)
+                {
+                    //找到当前物料的占用记录
+                    var itemSockoccupy = sklist.Where(s => s.icitem_id == sct.item_id).ToList();
+                    var num = parent_lack * sct.qty - itemSockoccupy.Sum(m => m.quantity);
+                    if (sct.erp_cls == 1)
+                    {
+                        //走自制
+                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = sct.bom_number,
+                            version = sct.version,
+                            packages = (int)sct.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        sct.kitting_time = sct.kitting_time.Value.AddDays((double)Day);
+                    }
+                    else if (sct.erp_cls == 3)
+                    {
+                        //采购申请
+                        var SRMPRDto = CreateSRMPR(sct, input.tenantId, input.factoryId, bangid, sct.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                        sct.kitting_time = SRMPRDto.lastStartTmie;
+                        SRMPRDtoList.Add(SRMPRDto);
+                    }
+                    else if (sct.erp_cls == 2)
+                    {
+                        //1.先生成委外工单。
+                        var mesorder = CreateMesOOder(sct, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                        sct.kitting_time = mesorder.ooentry_etime;
+                        orderList.Add(mesorder);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 可制占用计算---暂时未用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="kznun"></param>
+        public void Sockoccupy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, decimal kznun)
+        {
+            ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+            itemStockoccupyDto.bang_id = bangid;
+            if (item.stock_state == 1)
+            {
+                //成品库存占用
+                //slt.needCount
+                //可制物料占用
+                //slt.kz;如果是BOM,就展开BOM占用子物料
+                itemStockoccupyDto.icitem_id = item.item_id;
+                itemStockoccupyDto.quantity = item.needCount;
+            }
+            else if (item.stock_state == 2 || item.stock_state == 3)
+            {
+                itemStockoccupyDto.quantity = item.sqty;
+                var num = item.lack_qty;//可制满足的情况下,直接占用可制。
+                var sltChild = returnlist.Where(s => s.parent_id == item.id).ToList();
+                if (sltChild.Count() > 0)
+                {
+                    //有子集,则代表每条明细的库存加可制,才是父级的可制。
+                    foreach (var c in sltChild)
+                    {
+                        Sockoccupy(c, returnlist, bangid, num);
+                    }
+                }
+            }
+            //如果存在外购或者委外
+            else if (item.stock_state == 4 || item.stock_state == 5)
+            {
+                //根据最小颗粒度
+            }
+        }
+
+        /// <summary>
+        /// 计算物料是否缺料
+        /// </summary>
+        /// <param name="parent"></param>
+        /// <param name="bzlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sockoccupyList"></param>
+        public void calcTest2(BomChildExamineDto parent, List<BomChildExamineDto> bzlist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //从第二级开始循环
+            foreach (var item in bzlist)
+            {
+                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == 0).ToList();
+
+                //根据占用情况计算库存
+                Calczykc(item, parent, sockoccupyList);
+                //如果有子集,则丢入循环,判断下库存可制等信息。
+                calcTest2(item, childList, returnlist, sockoccupyList);
+            }
+        }
+
+        /// <summary>
+        /// 递归计算物料信息--暂未使用
+        /// </summary>
+        /// <param name="sublist"></param>
+        public void MaterialCalc(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            int maxIdx = sublist.Max(s => s.substitute_all_num);
+            for (int i = 0; i <= maxIdx; i++)
+            {
+                var group = sublist.Where(s => s.substitute_all_num == i).ToList();
+                // int boolCount = 0;//代表某一颗物料无需采购,可以自制,则集合+1。
+
+                //如果替代料库存不够,但是可制够,则也考虑使用优先级最高
+                foreach (var g in group)
+                {
+                    var parent = returnlist.Find(s => s.id == g.parent_id);
+                    //根据占用情况计算库存
+                    Calczykc(g, parent, sockoccupyList);
+                    /*if (g.stock_state != 1)
+                    {
+                        //判断此料是否BOM,如果是BOM,就考虑自制是否足够,此处递归检查子集
+                        var gChildList = returnlist.Where(s => s.parent_id == g.id).ToList();
+                        if (gChildList.Count > 0)
+                        {
+                            calcTest2(g, gChildList, returnlist, sockoccupyList);
+                            //如果是自制,则考虑自制够不够
+                            if (g.erp_cls == 1)
+                            {
+                                foreach (var cc in gChildList)
+                                {
+                                    //如果子物料是BOM,则当前物料的可制数量应该是子物料的库存加子物料的可制除以子物料的使用量
+                                    if (returnlist.Where(s => s.parent_id == cc.id).Count() > 0)
+                                    {
+                                        cc.kz = Math.Floor((cc.sqty + cc.kz) / g.qty);
+                                    }
+                                }
+                                g.kz = gChildList.Min(s => s.kz);//得到最小可制数量。
+                                
+                                //todo:如果是群组替代,可制数量应该跟随着主料来,不应该受限于最小可制单元。
+                                g.stock_state = gChildList.Max(s => s.stock_state);
+                                if (g.lack_qty <= g.kz)
+                                {
+                                    g.stock_state = 2;
+                                    boolCount++;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            g.kz = Math.Floor(g.sqty / g.qty);//自己不是BOM的情况下,算一下自己可制父级可以制造多少个,这个可制只是基于父级BOM才用来运算。
+                            //todo:申老师说,如果是苏州工厂,原材料有可能也是自制的。
+                            //所以这里在计算时,还可以直接拿缺料数量,去丢给苏州计算方法,得出原材料的库存加可制。
+                        }
+                    }
+                    else
+                    {
+                        boolCount++;
+                    }*/
+                }
+
+                /*if (boolCount == group.Count())
+                {
+                    //如果检查集合满足条数与群组里的物料条数相同,则代表这个群组的数量是满足的。
+                    group.ForEach(s =>
+                    {
+                        s.is_show = true;
+                    });
+                    break;//如果已经找到合适的替代群组关系,并且都不需要采购,则直接不继续检查了。
+                }*/
+            }
+        }
+
+        /// <summary>
+        /// 根据每个物料来实时计算占用情况
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sockoccupyList"></param>
+        public void Calczykc(BomChildExamineDto item, BomChildExamineDto parent, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //找到当前物料的占用记录
+            var itemSockoccupy = sockoccupyList.Where(s => s.icitem_id == item.item_id).ToList();
+            //计算库存减去占用
+            item.sqty -= itemSockoccupy.Sum(s => s.quantity);
+            //如果库存
+            item.sqty = item.sqty < 0 ? 0 : item.sqty;
+            if (parent.stock_state == 1 || parent.stock_state == -1)
+            {
+                item.stock_state = parent.stock_state;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                //判断缺料数量
+                item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+                item.lack_qty = item.lack_qty < 0 ? 0 : item.lack_qty;
+                //判断状态
+                item.stock_state = item.lack_qty > 0 ? 0 : 1;
+            }
+        }
+
+        #region 替代检查第一版,屏蔽
+        /*/// <summary>
+        /// 替代关系检查计算
+        /// </summary>
+        public void CalcIcitemSubstitute(List<BomChildExamineDto> returnlist, int count)
+        {
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
+            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
+            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
+            List<long> calcIds = new List<long>();
+            //先处理下最顶级的产品需要数量
+            returnlist[0].needCount = returnlist[0].qty * count;
+            returnlist[0].satisfyNum = returnlist[0].sqty;
+            returnlist[0].lack_qty = returnlist[0].needCount - returnlist[0].satisfyNum;
+            returnlist[0].is_show = true;
+            foreach (var item in returnlist)
+            {
+                //循环平铺整个资源检查的物料库存情况、缺料情况
+                CaclMaterialShortage(returnlist, item, count);
+            }
+            foreach (var item in returnlist)
+            {
+                //替代件不计算,替代件通过标准件的替代关系,去计算需要使用哪些物料
+                if (item.type == 1)
+                {
+                    continue;
+                }
+                CaclBomChildUseShortage(returnlist, item);
+            }
+        }
+
+        /// <summary>
+        /// 物料计算
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="item"></param>
+        /// <param name="count"></param>
+        public void CaclBomChildUseShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item)
+        {
+            //判断是否是BOM,如果是BOM,还需要向下展开
+            var bomchild = returnlist.Where(s => s.parent_id == item.id).ToList();
+            if (bomchild.Count > 0)
+            {
+                foreach (var child in bomchild)
+                {
+                    CaclBomChildUseShortage(returnlist, item);
+                    //取子级的最高状态
+                    item.stock_state = bomchild.Max(s => s.stock_state);
+                    item.kitting_time = bomchild.Max(s => s.kitting_time);
+                }
+            }
+            //var tolist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num).ToList();
+            //有替代关系
+            if (item.haveicsubs == 1)
+            {
+                //首先判断标准件库存是否满足。
+                //如果是BOM,也需要向下展开,看子物料是否满足。
+                //不满足的情况下,则需要展开替代关系,根据替代策略和替代方式,来判定替代件的库存。
+                //假设子BOM有替代关系,则子BOM的子物料,也是有替代关系存在的,需要展开来看。
+                //1.假设标准件库存满足,则不计算替代件关系。
+                //2.如果标准件不满足,则替代件开始计算并展示。
+                //注意:不管是否需要替代件,标准件都需要展开。没有使用到的物料,定义为无需求。如果子BOM库存足够,则不需要显示子物料和替代关系。
+                var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
+                //sublist找出当前含替代关系的标准件和替代件。
+                switch (item.substitute_strategy)
+                {
+                    case 0://整批
+                        break;
+                    case 1://混用
+                        break;
+                    case 2://整批加混用
+                        break;
+                }
+
+                
+                
+
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                }
+                else
+                {
+                    //取代
+                }
+            }
+            else//无替代关系
+            {
+                if (item.stock_state==0)
+                {
+                    item.use_qty = item.needCount;
+                    item.is_show = true;
+                }
+                else if (item.stock_state == 1)
+                {
+                    item.use_qty = item.sqty;
+                    // 缺料数量 item.lack_qty
+                    // 使用数量将库存全部使用了 item.use_qty = item.sqty;
+                    if (item.erp_cls == 2 || item.erp_cls == 3)
+                    {
+                        //委外、外购
+                        //生成委外工单、采购申请单
+                        //得到单据到货时间。
+                        //todo:初步设置为7天到货期,后期根据实际业务来补充修改。
+                        item.kitting_time = DateTime.Now.AddDays(7);
+                        item.stock_state = 2;
+                    }
+                    else if (item.erp_cls == 1)
+                    {
+                        //自制
+                        //调用产能计算,得到物料自制后的齐套时间。
+                        //todo:初步设置为7天完成,等沟通调用方法,来修改此处。
+                        item.kitting_time = DateTime.Now.AddDays(7);
+                        item.stock_state = 3;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 平铺物料缺料情况,展示所有主料+替代料的库存情况、缺料情况---需要修改成  库存情况、占用情况
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="item"></param>
+        /// <param name="count"></param>
+        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item, int count)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            //当前物料总共需要数量
+            item.needCount = parent.needCount * item.qty;
+            //当前库存可以满足的数量
+            item.satisfyNum = item.sqty;
+            //总需要数量减去库存量,得出缺料数量
+            item.lack_qty = item.needCount - item.satisfyNum;
+            //如果不满足,计算子物料,或者计算替代料
+            if (item.lack_qty < 0)
+            {
+                //库存满足
+                item.stock_state = 0;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                //找出自己的子集,存在子集则是BOM,不存在子集,则自己非BOM。
+                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).ToList();
+                if (childList.Count > 0)
+                {
+                    //自己是BOM
+                    decimal kz = 0;//当前BOM可制数量
+                    foreach (var child in childList)
+                    {
+                        //循环子集判断库存
+                        CaclMaterialShortage(returnlist, child, count);
+                        kz = kz > ((child.sqty+ child.kz) / child.qty) ? Math.Floor((child.sqty + child.kz) / child.qty) : kz;
+                    }
+                    //向下取整
+                    item.kz =Math.Floor(kz);
+                }
+                else
+                {
+                    //原材料没有可制数量。
+                    item.kz = 0;
+                    item.stock_state = 1;
+                }
+            }
+        }*/
+        #endregion
+
+        /// <summary>
+        /// 根据物料id获取物料4个提前期
+        /// </summary>
+        /// <param name="icItemIds">物料id</param>
+        /// <param name="tenantId">企业id</param>
+        /// <param name="factoryid">工厂id</param>
+        /// <returns></returns>
+        private List<ICItemLeadTimeDto> GetLeadTime(List<long> icItemIds, long tenantId, long factoryid)
+        {
+            ProjectionDefinitionBuilder<ic_factory_details> project = new ProjectionDefinitionBuilder<ic_factory_details>();
+            return _ic_factory_details.Find(p => icItemIds.Contains(p.icitem_id) && p.factory_id == factoryid && p.tenant_id == tenantId && !p.IsDeleted,
+                project.Include(p => p.icitem_id).Include(p => p.production_leadtime).Include(p => p.stock_leadtime).Include(p => p.transportation_leadtime).Include(p => p.order_leadtime)).Result.
+                Select(x => new ICItemLeadTimeDto { item_id = x.icitem_id, transportation_leadtime = x.transportation_leadtime, stock_leadtime = x.stock_leadtime, production_leadtime = x.production_leadtime, order_leadtime = x.order_leadtime }).AsQueryable<ICItemLeadTimeDto>().ToList();
+        }
+
+        //根据物料id获取物料供应商
+        private List<ic_item_pur> GetSupplier(List<long> icItemIds, long tenantId, long factoryid)
+        {
+            return _ic_item_pur.Find(p => icItemIds.Contains(p.icitem_id) && p.tenant_id == tenantId && p.factory_id == factoryid && !p.IsDeleted).Result;
+        }
+
+        //根据物料id获取物料采购计划表
+        private List<ic_plan> GetICPlan(List<long> icItemIds, long tenantId, long factoryid)
+        {
+            return _ic_plan.Find(p => icItemIds.Contains(p.icitem_id) && p.tenant_id == tenantId && p.factory_id == factoryid && !p.IsDeleted).Result;
+        }
+
+
+        /// <summary>
+        /// 检查在途量
+        /// </summary>
+        /// <param name="returnlist">物料列表</param>
+        /// <param name="factoryid">工厂id</param>
+        /// <param name="deliveryDate">销售订单交付日期</param>
+        /// <returns></returns>
+        private async Task<List<ICItemDateDto>> CheckOnOrder(List<BomChildExamineDto> returnlist, long tenantId, long factoryid, DateTime deliveryDate, long bangid)
+        {
+            //ToDo:企业Id,数据状态过滤以及isdeleted
+            var po_list = _srm_po_list.Find(p => returnlist.Select(x => x.item_id).Contains(p.icitem_id.Value) && p.tenant_id == tenantId && p.factory_id == factoryid && p.rarrdate >= DateTime.Now && p.rarrdate < deliveryDate && !p.IsDeleted).Result;
+            var itemlist = new List<ICItemDateDto>();//需要生成采购申请单的物料信息
+            var leadTimeList = GetLeadTime(returnlist.Select(p => p.item_id).ToList(), tenantId, factoryid);//提前期列表
+            var supplierList = GetSupplier(returnlist.Select(p => p.item_id).ToList(), tenantId, factoryid);//供应商列表
+            var planList = GetICPlan(returnlist.Select(p => p.item_id).ToList(), tenantId, factoryid);//plan列表
+            foreach (var item in returnlist)
+            {
+                //缺料
+                if (item.lack_qty > 0)
+                {
+                    var itemPO = po_list.FindAll(x => x.icitem_id == item.item_id).OrderBy(v => v.rarrdate).ToList();
+                    if (itemPO.Count <= 0 || itemPO.Sum(p => (p.qty - p.esqty)) < item.lack_qty)
+                    {
+                        //外购生成采购申请单
+                        if (item.erp_cls == 3)
+                        {
+                            //DateTime lastTime = CreateSRMPR(item, tenantId, factoryid, bangid, 2, leadTimeList, supplierList, planList, deliveryDate);
+                            //itemlist.Add(new ICItemDateDto { item_id = item.item_id, dateTime = lastTime });
+                        }
+                        else if (item.erp_cls == 2)
+                        {
+                            //委外生成委外采购申请单和委外工单
+                            //DateTime lastTime = CreateSRMPR(item, tenantId, factoryid, bangid, 1, leadTimeList, supplierList, planList, deliveryDate);
+                            //CreateMesOOder(item, tenantId, factoryid, bangid, leadTimeList, supplierList, deliveryDate);
+                            //itemlist.Add(new ICItemDateDto { item_id = item.item_id, dateTime = lastTime });
+                        }
+                    }
+                    else
+                    {
+                        decimal? itemPOQty = 0;//当前物料已抵扣数量
+                        for (int i = 0; i < itemPO.Count; i++)
+                        {
+                            if (itemPOQty + itemPO[i].qty - itemPO[i].esqty >= item.lack_qty)
+                            {
+                                //在途满足,写占用表
+                                itemlist.Add(new ICItemDateDto { item_id = itemPO[i].icitem_id.Value, dateTime = itemPO[i].rarrdate });
+                                srm_po_occupy po_Occupy = new srm_po_occupy();
+                                po_Occupy.GenerateNewId();
+                                po_Occupy.polist_id = itemPO[i].po_id;//采购订单id
+                                po_Occupy.polist_row = itemPO[i].polist_row;//采购订单行号
+                                po_Occupy.eid = 111;//客户订单行id
+                                po_Occupy.bill_no = 111;//客户订单id
+                                po_Occupy.type = "在途占用";//类型
+                                po_Occupy.entry_id = 1;//行号
+                                po_Occupy.qty = item.lack_qty - itemPOQty;//占用量
+                                po_Occupy.stime = DateTime.Now;//开始时间
+                                po_Occupy.etime = deliveryDate;//结束时间
+                                po_Occupy.state = 1;//占用状态
+                                po_Occupy.cby = "";//变更人
+                                po_Occupy.creason = "";//变更原因
+                                po_Occupy.ctime = DateTime.Now;//变更时间
+                                po_Occupy.bang_id = bangid;
+                                await _srm_po_occupy.InsertOne(po_Occupy);
+                                break;
+                            }
+                            else
+                            {
+                                //不满足逐步扣减
+                                itemPOQty = itemPOQty + itemPO[i].qty - itemPO[i].esqty;
+                                srm_po_occupy po_Occupy = new srm_po_occupy();
+                                po_Occupy.GenerateNewId();
+                                po_Occupy.polist_id = itemPO[i].po_id;//采购订单id
+                                po_Occupy.polist_row = itemPO[i].polist_row;//采购订单行号
+                                po_Occupy.eid = 111;//客户订单行id
+                                po_Occupy.bill_no = 111;//客户订单id
+                                po_Occupy.type = "在途占用";//类型
+                                po_Occupy.entry_id = 1;//行号
+                                po_Occupy.qty = itemPO[i].qty - itemPO[i].esqty;//占用量
+                                po_Occupy.stime = DateTime.Now;//开始时间
+                                po_Occupy.etime = deliveryDate;//结束时间
+                                po_Occupy.state = 1;//占用状态
+                                po_Occupy.cby = "";//变更人
+                                po_Occupy.creason = "";//变更原因
+                                po_Occupy.ctime = DateTime.Now;//变更时间
+                                po_Occupy.bang_id = bangid;
+                                await _srm_po_occupy.InsertOne(po_Occupy);
+                            }
+                        }
+                    }
+                }
+            }
+            return itemlist;
+        }
+
+        ///// <summary>
+        ///// 生成委外工单
+        ///// </summary>
+        ///// <param name="returnlist"></param>
+        ///// <param name="factoryid"></param>
+        //private DateTime CreateMesOOder(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, DateTime deliveryDate)
+        //{
+        //    mes_oorder oOrder = new mes_oorder();
+        //    oOrder.GenerateNewId();
+        //    oOrder.oorder_no = getOrderNum("WW");//生产工单编号
+        //    oOrder.oorder_type = "委外工单";//生产工单类型
+        //    oOrder.oorder_date = DateTime.Now;//委外订单日期
+        //    oOrder.oorder_state = "已提交";//订单状态
+        //    oOrder.ooentry_prd = 10000;//生产组织
+        //    oOrder.ooentry_prdname = "1000";//生产组织名称
+        //    oOrder.ooentry_wrkc = 10000;//工作中心id
+        //    oOrder.ooentry_wrkcname = "10001";//工作中心名称
+        //    oOrder.planner_num = "wwww";//计划员工号
+        //    oOrder.planner_name = "qqq";//计划员名称
+        //    oOrder.ooentry_stime = DateTime.Now;//计划开工日期
+        //    oOrder.ooentry_etime = DateTime.Now;//计划完工日期
+        //    oOrder.product_code = "产品代码";//产品代码
+        //    oOrder.ffms_number = "1000";//fms旧料号
+        //    oOrder.product_name = "test";//产品名称
+        //    oOrder.specification_model = returnlist.model;//规格型号
+        //    oOrder.bom_number = "";//bom编码
+        //    oOrder.unit = returnlist.unit;//单位
+        //    oOrder.morder_progress = "";//工单进度
+        //    oOrder.morder_production_number = returnlist.lack_qty;//工单生产数量(计划数量)
+        //    oOrder.need_number = returnlist.lack_qty;//需求数量
+        //    oOrder.remaining_number = returnlist.lack_qty;//剩余可用数量
+        //    oOrder.work_number = 0;//报工数量
+        //    oOrder.inspection_number = 0;//报检数量
+        //    oOrder.qualified_number = 0;//合格数量
+        //    oOrder.inventory_number = 0;//入库数量
+        //    oOrder.notice_qty = 0;//已开通知单数量
+        //    oOrder.moentry_on = 1;//启动状态
+        //    //oOrder.start_time = DateTime.Now;//开始时间
+        //    //oOrder.pause_time = DateTime.Now;//最近暂停时间
+        //    //oOrder.restart_time = DateTime.Now;//最近重启时间
+        //    oOrder.project_name = returnlist.item_name;//项目名称
+        //    oOrder.sent_status = 1;//发料状态 1-待发料  2-已发料
+        //    oOrder.production_unit = returnlist.unit;//加工单位
+        //    oOrder.production_unit_code = "";//加工单位编码
+        //    oOrder.need_icitem_status = 1;//所需物料是否充足  1-充足 0-缺料
+        //    oOrder.tenant_id = tenantId;
+        //    oOrder.factory_id = factoryid;
+        //    oOrder.bang_id = bangId;
+        //    _mes_oorder.InsertOne(oOrder);
+        //    return DateTime.Now;
+        //}
+
+        /// <summary>
+        /// 生成委外工单
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="factoryid"></param>
+        private mes_oorder CreateMesOOder(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, DateTime deliveryDate)
+        {
+            mes_oorder oOrder = new mes_oorder();
+            oOrder.GenerateNewId();
+            oOrder.oorder_no = getOrderNum("WW");//生产工单编号
+            oOrder.oorder_type = "委外工单";//生产工单类型
+            oOrder.oorder_date = DateTime.Now;//委外订单日期
+            oOrder.oorder_state = "已提交";//订单状态
+            oOrder.ooentry_prd = 10000;//生产组织
+            oOrder.ooentry_prdname = "1000";//生产组织名称
+            oOrder.ooentry_wrkc = 10000;//工作中心id
+            oOrder.ooentry_wrkcname = "10001";//工作中心名称
+            oOrder.planner_num = "wwww";//计划员工号
+            oOrder.planner_name = "qqq";//计划员名称
+            oOrder.ooentry_stime = DateTime.Now;//计划开工日期
+            oOrder.ooentry_etime = DateTime.Now;//计划完工日期
+            oOrder.product_code = "产品代码";//产品代码
+            oOrder.ffms_number = "1000";//fms旧料号
+            oOrder.product_name = "test";//产品名称
+            oOrder.specification_model = returnlist.model;//规格型号
+            oOrder.bom_number = "";//bom编码
+            oOrder.unit = returnlist.unit;//单位
+            oOrder.morder_progress = "";//工单进度
+            oOrder.morder_production_number = returnlist.lack_qty;//工单生产数量(计划数量)
+            oOrder.need_number = returnlist.lack_qty;//需求数量
+            oOrder.remaining_number = returnlist.lack_qty;//剩余可用数量
+            oOrder.work_number = 0;//报工数量
+            oOrder.inspection_number = 0;//报检数量
+            oOrder.qualified_number = 0;//合格数量
+            oOrder.inventory_number = 0;//入库数量
+            oOrder.notice_qty = 0;//已开通知单数量
+            oOrder.moentry_on = 1;//启动状态
+            //oOrder.start_time = DateTime.Now;//开始时间
+            //oOrder.pause_time = DateTime.Now;//最近暂停时间
+            //oOrder.restart_time = DateTime.Now;//最近重启时间
+            oOrder.project_name = returnlist.item_name;//项目名称
+            oOrder.sent_status = 1;//发料状态 1-待发料  2-已发料
+            oOrder.production_unit = returnlist.unit;//加工单位
+            oOrder.production_unit_code = "";//加工单位编码
+            oOrder.need_icitem_status = 1;//所需物料是否充足  1-充足 0-缺料
+            oOrder.tenant_id = tenantId;
+            oOrder.factory_id = factoryid;
+            oOrder.bang_id = bangId;
+            return oOrder;
+            //_mes_oorder.InsertOne(oOrder);
+        }
+
+
+        ///// <summary>
+        ///// 生成采购申请单,颗粒度是一个物料一个单,没必要弄列表
+        ///// </summary>
+        ///// <param name="returnlist"></param>
+        ///// <param name="factoryid"></param>
+        ///// <param name="orderType">2委外采购申请单,3采购申请单</param>
+        //private DateTime CreateSRMPR(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, int orderType, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, List<ic_plan> planList, DateTime deliveryDate)
+        //{
+        //    var leadTime = iCItemLeadTimes.Find(x => x.item_id == returnlist.item_id);
+        //    var supplier = supplierList.Find(x => x.icitem_id == returnlist.item_id);//默认取第一个供应商
+        //    var plan = planList.Find(x => x.icitem_id == returnlist.item_id);
+        //    if (leadTime == null || supplier == null || plan == null)
+        //    {
+        //        throw new NotImplementedException("未找到物料ic_factory_details或ic_item_pur或ic_plan信息!");
+        //    }
+        //    srm_pr_main srm_Pr = new srm_pr_main();
+        //    srm_Pr.GenerateNewId();
+        //    srm_Pr.pr_billno = getOrderNum("PR");//pr单号
+        //    srm_Pr.pr_mono = "";//关联工单号
+        //    srm_Pr.entity_id = 1;//工单行号
+        //    srm_Pr.pr_purchaseid = supplier.supplier_id;//供应商id  
+        //    srm_Pr.pr_purchasenumber = supplier.supplier_number;//供应商编码
+        //    srm_Pr.pr_purchasename = supplier.supplier_name;//供应商名称
+        //    srm_Pr.pr_purchaser = supplier.purcher;//采购员
+        //    srm_Pr.pr_purchaser_num = "";//采购员工号(采购信息表)
+        //    srm_Pr.pr_rqty = returnlist.lack_qty;//需求数量
+        //    srm_Pr.pr_aqty = returnlist.lack_qty;//申请数量
+        //    srm_Pr.pr_sqty = returnlist.lack_qty;//建议数量
+        //    srm_Pr.icitem_id = returnlist.item_id;//物料id
+        //    srm_Pr.icitem_name = returnlist.item_name;//物料名称
+        //    srm_Pr.pr_order_type = 1;//单据类型
+        //    srm_Pr.pr_ssend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//系统建议下单日期
+        //    srm_Pr.pr_sarrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//系统建议到达日期(建议到货日期)
+        //    srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+        //    srm_Pr.pr_parrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//计划到达日期
+        //    srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+        //    srm_Pr.pr_sysprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//系统价格(含税)
+        //    srm_Pr.pr_orderprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//订单价格(含税)
+        //    srm_Pr.pr_price = supplier.netpurchase_price;//采购净价(不含税)
+        //    srm_Pr.pr_rate = supplier.taxrate;//税率
+        //    srm_Pr.pr_unit = returnlist.unit;//单位
+        //    srm_Pr.state = 1;//状态
+        //    srm_Pr.old_apply_aqty = 0;//已申请数量
+        //    srm_Pr.pr_type = orderType;//申请类型
+        //    srm_Pr.currencytype = supplier.currency_type;//币种
+        //    srm_Pr.secInv_ratio = plan.secinv_ratio;//安全库存触发采购比例
+        //    srm_Pr.tenant_id = tenantId;
+        //    srm_Pr.factory_id = factoryid;
+        //    srm_Pr.bang_id = bangId;
+        //    _srm_pr_main.InsertOne(srm_Pr);
+        //    decimal? totalLeadTime = leadTime.transportation_leadtime + leadTime.stock_leadtime + leadTime.production_leadtime + leadTime.order_leadtime;
+        //    return deliveryDate.AddDays((double)totalLeadTime * -1);//减去提前期
+        //}
+
+        /// <summary>
+        /// 生成采购申请单,颗粒度是一个物料一个单,没必要弄列表
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="factoryid"></param>
+        /// <param name="orderType">2委外采购申请单,3采购申请单</param>
+        private SRMPRDto CreateSRMPR(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, int orderType, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, List<ic_plan> planList, DateTime deliveryDate)
+        {
+            SRMPRDto sRMPR = new SRMPRDto();
+            srm_pr_main srm_Pr = new srm_pr_main();
+            var leadTime = iCItemLeadTimes.Find(x => x.item_id == returnlist.item_id);
+            var supplier = supplierList.Find(x => x.icitem_id == returnlist.item_id);//默认取第一个供应商
+            var plan = planList.Find(x => x.icitem_id == returnlist.item_id);
+            if (leadTime == null || supplier == null || plan == null)
+            {
+                sRMPR.srm_Pr_Main = null;
+                sRMPR.lastStartTmie = deliveryDate.AddDays(7 * -1);//减去提前期
+                return sRMPR;
+                //throw new NotImplementedException("未找到物料ic_factory_details或ic_item_pur或ic_plan信息!");
+            }
+            
+            srm_Pr.GenerateNewId();
+            srm_Pr.pr_billno = getOrderNum("PR");//pr单号
+            srm_Pr.pr_mono = "";//关联工单号
+            srm_Pr.entity_id = 1;//工单行号
+            srm_Pr.pr_purchaseid = supplier.supplier_id;//供应商id  
+            srm_Pr.pr_purchasenumber = supplier.supplier_number;//供应商编码
+            srm_Pr.pr_purchasename = supplier.supplier_name;//供应商名称
+            srm_Pr.pr_purchaser = supplier.purcher;//采购员
+            srm_Pr.pr_purchaser_num = "";//采购员工号(采购信息表)
+            srm_Pr.pr_rqty = returnlist.lack_qty;//需求数量
+            srm_Pr.pr_aqty = returnlist.lack_qty;//申请数量
+            srm_Pr.pr_sqty = returnlist.lack_qty;//建议数量
+            srm_Pr.icitem_id = returnlist.item_id;//物料id
+            srm_Pr.icitem_name = returnlist.item_name;//物料名称
+            srm_Pr.pr_order_type = 1;//单据类型
+            srm_Pr.pr_ssend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//系统建议下单日期
+            srm_Pr.pr_sarrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//系统建议到达日期(建议到货日期)
+            srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+            srm_Pr.pr_parrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//计划到达日期
+            srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+            srm_Pr.pr_sysprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//系统价格(含税)
+            srm_Pr.pr_orderprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//订单价格(含税)
+            srm_Pr.pr_price = supplier.netpurchase_price;//采购净价(不含税)
+            srm_Pr.pr_rate = supplier.taxrate;//税率
+            srm_Pr.pr_unit = returnlist.unit;//单位
+            srm_Pr.state = 1;//状态
+            srm_Pr.old_apply_aqty = 0;//已申请数量
+            srm_Pr.pr_type = orderType;//申请类型
+            srm_Pr.currencytype = supplier.currency_type;//币种
+            srm_Pr.secInv_ratio = plan.secinv_ratio;//安全库存触发采购比例
+            srm_Pr.tenant_id = tenantId;
+            srm_Pr.factory_id = factoryid;
+            srm_Pr.bang_id = bangId;
+            //_srm_pr_main.InsertOne(srm_Pr);
+            decimal? totalLeadTime = leadTime.transportation_leadtime + leadTime.stock_leadtime + leadTime.production_leadtime + leadTime.order_leadtime;
+            
+            sRMPR.srm_Pr_Main = srm_Pr;
+            sRMPR.lastStartTmie = deliveryDate.AddDays((double)totalLeadTime * -1);//减去提前期
+            return sRMPR;
+        }
+
+        // 生成订单编号 字母+年月日+8位随机数+时间戳
+        private string getOrderNum(string preCode)
+        {
+            string Dates = DateTime.Now.ToString("yyyyMMdd");//获取当前时间
+            Random Rdm = new Random(Guid.NewGuid().GetHashCode());//随机数
+            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);//时间戳
+            string newts = Convert.ToInt64(ts.TotalMilliseconds).ToString();//时间戳          
+            string new_orderNum = preCode + Dates + Rdm.Next(0, 100000000) + newts;
+            return new_orderNum;
+        }
+    }
+}

+ 1048 - 0
MicroServices/Business/Back/在制工单实现/含在制实现,在制循环查库未处理完成.txt

@@ -0,0 +1,1048 @@
+ /// <summary>
+        /// BOM预处理
+        /// </summary>
+        /// <param name="orderid"></param>
+        /// <param name="BomId"></param>
+        /// <param name="Quantity"></param>
+        public List<BomChildExamineDto> BomPretreatment(long? BomId, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist)
+        {
+            if (BomId == null)
+            {
+                //throw new bu
+            }
+            List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+
+            var bom = bomlist.Find(s => s.Id == BomId);
+            if (bom == null)
+            {
+                return returnlist;
+            }
+
+            var dto = new BomChildExamineDto();
+            dto.item_id = bom.icitem_id;
+            dto.bom_id = BomId.Value;
+            dto.bom_number = bom.bom_number;
+            dto.level = 1;
+            dto.id = help.NextId();
+            dto.parent_id = help.NextId();
+            dto.qty = 1;
+            dto.num = "1";
+            dto.isbom = 1;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            int type = 0;
+            GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            return returnlist;
+        }
+
+        /// <summary>
+        /// BOM预处理层级组装
+        /// </summary>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="dto"></param>
+        /// <param name="returnlist"></param>
+        public void GetBomList(List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, BomChildExamineDto dto, List<BomChildExamineDto> returnlist, int type)
+        {
+            int level = dto.level + 1;//初始化定义level层级
+
+            var bom = bomlist.Where(s => s.Id == dto.bom_id).FirstOrDefault();
+            ic_item item = new ic_item();
+            if (bom != null)
+            {
+                item = icitemlist.Where(a => a.Id == bom.icitem_id).FirstOrDefault();
+            }
+            else
+            {
+                item = icitemlist.Where(a => a.Id == dto.item_id).FirstOrDefault();
+            }
+            if (item == null)
+            {
+                return;
+            }
+            dto.item_id = item.Id;
+            dto.item_name = bom.item_name;
+            dto.item_code = bom.item_number;
+            dto.model = item.model;
+            dto.unit = bom.unit;
+            dto.erp_cls = item.erp_cls;
+            dto.erp_cls_name = item.erp_cls_name;
+            dto.type = type;
+            dto.item_number = item.number;
+
+            //var bdto = ObjectMapper.Map<ic_bom,BomChildExamineDto>(bom);
+            returnlist.Add(dto);
+            var childlist = bomchildlist.Where(a => a.bom_id == bom.Id).ToList();
+
+            int idx = 1;
+            foreach (var c in childlist)
+            {
+                string childNum = dto.num + "." + idx.ToString();
+                var icitem = icitemlist.Where(a => a.Id == c.icitem_id).FirstOrDefault();
+                var childBom = bomlist.Where(a => a.icitem_id == c.icitem_id).FirstOrDefault();
+                //如果此明细查的到BOM信息,则代表此child是一个子BOM。
+                if (childBom != null)
+                {
+                    var cdto = new BomChildExamineDto();
+                    cdto.id = help.NextId();
+                    cdto.level = level;
+                    cdto.parent_id = dto.id;
+                    cdto.bom_child_id = c.Id;
+                    cdto.qty = c.qty.Value;
+                    cdto.backflush = c.backflush;
+                    cdto.num = childNum;
+                    cdto.isbom = 1;
+                    cdto.is_replace = c.is_replace;
+                    cdto.haveicsubs = c.haveicsubs;
+                    cdto.substitute_code = c.substitute_code;
+                    cdto.icitem_ids = c.icitem_ids;
+                    cdto.type = type;
+                    cdto.item_id = childBom.icitem_id;
+                    cdto.bom_id = childBom.Id;
+                    cdto.bom_number = childBom.bom_number;
+                    //递归寻找子级
+                    GetBomList(bomlist, bomchildlist, icitemlist, cdto, returnlist, type);
+                }
+                else
+                {
+                    if (icitem != null)
+                    {
+                        var childDto = new BomChildExamineDto();
+                        childDto.level = level;
+                        childDto.bom_id = dto.bom_id;
+                        childDto.bom_child_id = c.Id;
+                        childDto.id = help.NextId();
+                        childDto.parent_id = dto.id;
+                        childDto.item_id = icitem.Id;
+                        childDto.item_name = icitem.name;
+                        childDto.item_code = icitem.number;
+                        childDto.num = childNum;
+                        childDto.model = icitem.model;
+                        childDto.unit = c.unit;
+                        childDto.erp_cls = icitem.erp_cls;
+                        childDto.erp_cls_name = icitem.erp_cls_name;
+                        childDto.backflush = c.backflush;
+                        childDto.qty = c.qty.Value;
+                        childDto.isbom = 0;
+                        childDto.is_replace = c.is_replace;
+                        childDto.haveicsubs = c.haveicsubs;
+                        childDto.substitute_code = c.substitute_code;
+                        childDto.icitem_ids = c.icitem_ids;
+                        childDto.type = type;
+                        childDto.item_number = icitem.number;
+                        returnlist.Add(childDto);
+                    }
+                }
+                idx++;
+            }
+
+        }
+
+
+        /// <summary>
+        /// BOM替代关系预处理
+        /// </summary>
+        public void BomSubstitute(List<BomChildExamineDto> returnlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, List<ic_substitute> sublist, List<ic_substitute_all> suballlist, List<ic_substitute_all_dtl> subdtllist)
+        {
+            List<long> childidList = new List<long>();
+            int type = 1;
+            List<BomChildExamineDto> addlist = new List<BomChildExamineDto>();
+
+            //除顶级外,其他层级关系全带出来。生成平铺
+            foreach (var item in returnlist)
+            {
+                //最顶级、虚拟件
+                if (item.level == 1 || item.erp_cls == 4 || childidList.Contains(item.bom_child_id.GetValueOrDefault()))
+                {
+                    continue;
+                }
+                //有替代关系
+                if (item.haveicsubs != 1)
+                {
+                    continue;
+                }
+                if (!string.IsNullOrEmpty(item.icitem_ids))
+                {
+                    long cid = 1;
+                    var cids = item.icitem_ids.Split(',');
+                    foreach (var c in cids)
+                    {
+                        if (long.TryParse(c, out cid))
+                        {
+                            childidList.Add(cid);
+                        }
+                    }
+                }
+
+
+                //找到当前物料的替代群组关系集
+                var sl = sublist.Find(s => s.substitute_code == item.substitute_code);
+                if (sl != null)
+                {
+                    var sall = suballlist.Where(s => s.substitute_id == sl.Id).ToList();
+                    foreach (var sal in sall)
+                    {
+                        var sadl = subdtllist.Where(s => s.substitute_allid == sal.Id).ToList();
+                        foreach (var dtl in sadl)
+                        {
+                            if (sal.main_material.GetValueOrDefault() != 1)
+                            {
+                                //递归将替代关系组装出来。
+                                SubstitutePretreatment(sl, sal, dtl, item, addlist, icitemlist, bomlist, bomchildlist, type);
+                            }
+                            else
+                            {
+                                //将主料赋值上属性
+                                var dtlitem = returnlist.Find(s => s.item_id == dtl.icitem_id && s.level == item.level);
+                                dtlitem.substitute_all_num = sal.order_num;//群组优先级
+                            }
+                        }
+
+
+
+                    }
+                }
+            }
+            returnlist.AddRange(addlist);
+        }
+
+        /// <summary>
+        /// 替代关系递归组装出来
+        /// </summary>
+        /// <param name="sal"></param>
+        /// <param name="dtl"></param>
+        /// <param name="toDto"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        public void SubstitutePretreatment(ic_substitute sl, ic_substitute_all sal, ic_substitute_all_dtl dtl, BomChildExamineDto toDto, List<BomChildExamineDto> returnlist, List<ic_item> icitemlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, int type)
+        {
+            //如果dtl对应的icitem是BOM,还需要向下继续展开。
+
+            //List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+            var dto = new BomChildExamineDto();
+            var bom = bomlist.Where(s => s.icitem_id == dtl.icitem_id).FirstOrDefault();
+            var icitem = icitemlist.Find(s => s.Id == dtl.icitem_id);
+            if (icitem == null)
+            {
+                return;
+            }
+            dto.id = help.NextId();
+            dto.level = toDto.level;
+            dto.parent_id = toDto.parent_id;
+            dto.item_id = icitem.Id;
+            dto.item_name = icitem.name;
+            dto.item_code = icitem.number;
+            dto.num = toDto.num;
+            dto.model = icitem.model;
+            dto.unit = icitem.unit;
+            dto.erp_cls = icitem.erp_cls;
+            dto.erp_cls_name = icitem.erp_cls_name;
+            dto.backflush = toDto.backflush;
+            //dto.qty = toDto.qty;
+            //dto.replace_amount = dtl.replace_amount.Value;
+            dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            dto.substitute_strategy = sl.substitute_strategy == null ? 0 : sl.substitute_strategy.Value;//替代策略
+            dto.substitute_mode = sl.substitute_mode == null ? 0 : sl.substitute_mode.Value;//替代方式
+            dto.type = type;
+            dto.substitute_all_num = sal.order_num;//群组优先级
+            if (bom != null)
+            {
+                dto.bom_id = bom.Id;
+
+                dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+                dto.isbom = 1;
+                dto.is_replace = 0;
+                dto.haveicsubs = 0;
+                dto.substitute_code = "";
+                dto.icitem_ids = "";
+                GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            }
+            else
+            {
+                dto.bom_id = null;
+                dto.isbom = 0;
+                returnlist.Add(dto);
+            }
+        }
+
+        /// <summary>
+        /// 计算物料库存量
+        /// </summary>
+        /// <param name="returnlist"></param>
+        public void BomStock(List<BomChildExamineDto> returnlist)
+        {
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
+            //获取当前工厂下物料库存数据
+            List<long> icitemIds = returnlist.Select(c => c.item_id).ToList();
+            var stocklist = _ic_item_stock.GetManyByCondition(p => p.factory_id == param.factoryId && icitemIds.Contains(p.icitem_id)).Result;
+            //计算剩余库存
+            foreach (var item in returnlist)
+            {
+                if (item.erp_cls == 4)//虚拟件不计算
+                {
+                    continue;
+                }
+                //非虚拟件
+                //当前物料的库存数量
+                decimal stockQty = stocklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.sqty.GetValueOrDefault());
+                //获取当前订单其他订单行当前物料的占用数量
+                //decimal otherStockQty = occupylist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
+                //当前订单行物料库存情况
+                //item.sqty = stockQty - otherStockQty;
+                item.sqty = stockQty;
+            }
+        }
+
+        /// <summary>
+        /// 替代关系计算
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="orderid"></param>
+        /// <param name="count"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid, decimal count, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item_stockoccupy> sklist, crm_seorderentry sentrys,List<ic_item> icitemlist)
+        {
+            //第一级
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
+            var childList = returnlist.Where(s => s.parent_id == returnlist[0].id && s.type == 0).OrderBy(s => s.num).ToList();
+
+
+            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
+            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
+            List<long> calcIds = new List<long>();
+            //先处理下最顶级的产品需要数量
+            returnlist[0].needCount = returnlist[0].qty * count;
+            returnlist[0].lack_qty = returnlist[0].needCount - returnlist[0].sqty;
+
+            foreach (var item in returnlist)
+            {
+                if (item.level == 1)
+                {
+                    continue;
+                }
+                //循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
+                CaclMaterialShortage(returnlist, item, count);
+            }
+            Mes_MorderDto mes_MorderDto = new Mes_MorderDto();
+            if (returnlist[0].lack_qty > 0)
+            {
+                //获取物料详情
+                var ic_item = icitemlist.Find(s => s.Id == returnlist[0].item_id);
+                var mooccupylist = _morderAppService.CheckMorder(returnlist[0].bom_number, returnlist[0].lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                returnlist[0].mo_qty = moo_qty;
+                if (moo_qty == returnlist[0].lack_qty)
+                {
+                    //在制完全足够
+                    returnlist[0].lack_qty = 0;
+                    returnlist[0].satisfy_time = mooccupylist[0].moo_etime;
+                    returnlist[0].stock_state = 1;
+                    return;
+                }
+                else
+                {
+                    //占用不够,占用后减少缺料数量
+                    returnlist[0].lack_qty -= moo_qty;
+                    //先设定在制的齐套时间
+                    returnlist[0].satisfy_time = mooccupylist[0]?.moo_etime;
+                    returnlist[0].stock_state = 0;
+                    //生成主工单
+                    GenerateMorderDto generateMorderDto = new GenerateMorderDto()
+                    {
+                        seorderentry = sentrys,
+                        ic_Item = ic_item,
+                        BomNumber = returnlist[0].bom_number,
+                        version = returnlist[0].version,
+                        number = returnlist[0].item_number,
+                        Quantity = returnlist[0].lack_qty,
+                        morder_type = "销售工单",
+                        work_order_type = "常规工单",
+                        morder_state = "初始",
+
+                    };
+                    //生成主工单
+                    mes_MorderDto = _morderAppService.GenerateMorder(generateMorderDto);
+                }
+            }
+            else {
+                returnlist[0].satisfy_time = DateTime.Now;
+                returnlist[0].stock_state = 1;
+                return;
+            }
+
+            //这是从上往下展开计算缺料和可制
+            calcTest2(returnlist[0], childList, returnlist, sklist);
+            //returnlist[0].kz = childList.Min(s => s.kz);//得到最小可制数量。
+            //再加个循环,来根据替代关系里的检查结果,根据规则明确使用和生成占用关系。
+            CalcIcitem(childList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+            returnlist[0].kitting_time = childList.Max(s => s.kitting_time);
+            //这里更新产品得满足时间。
+            if (mes_MorderDto != null)
+            {
+                //主工单最后计算满足日期
+                var mes_Morders = mes_MorderDto.mes_Morders.Where(x => x.parent_id == null).FirstOrDefault();
+                if (mes_Morders != null)
+                {
+                    if (!string.IsNullOrEmpty(mes_Morders.bom_number))
+                    {
+                        //var ProductiveDate = ProductiveExamine(mes_Morders.bom_number, returnlist[0].version, (int)mes_Morders.morder_production_number.Value);
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = mes_Morders.bom_number,
+                            version = returnlist[0].version,
+                            packages = (int)mes_Morders.morder_production_number.Value,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var plan = planList.Find(x => x.icitem_id == returnlist[0].item_id);
+                        var ProductiveDate = _productExamineAppService.ProductiveExamine(prodExamine);
+                        var Day = ProductiveDate.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        mes_Morders.moentry_sys_stime = returnlist[0].kitting_time.Value.AddDays(1);//数据齐套完成后隔天开始生产;
+                        //结束日期=开始时间+生产时长+自检提前期+入库提前期+发运提前期;
+                        var LeadTime = Day + plan.self_inspection_date.Value + plan.Shipping_date.Value + plan.Warehousing_date.Value;
+                        mes_Morders.moentry_sys_etime = mes_Morders.moentry_sys_stime.Value.AddDays((double)Day);
+                        mes_Morders.morder_need_time = ProductiveDate.Result;
+                        //满足资源检查的时间需加上提前期
+                        returnlist[0].satisfy_time = mes_Morders.moentry_sys_stime.Value.AddDays((double)LeadTime);
+                    }
+                    //批量保存 后期考虑子工单
+                    _mes_morder.InsertMany(mes_MorderDto.mes_Morders);
+                    _mes_moentry.InsertMany(mes_MorderDto.mes_Moentries);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 循环计算物料情况
+        /// </summary>
+        /// <param name="childList"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="orderid"></param>
+        /// <param name="input"></param>
+        /// <param name="sklist"></param>
+        /// <param name="plan_date"></param>
+        public void CalcIcitem(List<BomChildExamineDto> childList, List<BomChildExamineDto> returnlist, long bangid, SeorderentryDto input, List<ic_item_stockoccupy> sklist, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            foreach (var item in childList)
+            {
+                var parent = returnlist.Find(s => s.id == item.parent_id);
+                if (parent.stock_state == 0)
+                {
+                    if (item.haveicsubs == 1)
+                    {
+                        //如果有替代关系,根据群组来明确使用哪个群组的替代料。按整批和混用逻辑来算
+                        // 如果有群组替代,就移除掉被检查过的记录 item.icitem_ids
+                        CalcStrategy(item, returnlist, bangid, sklist, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        Calczykc(item, parent, sklist);
+
+                        //直接占用库存,缺料就生成采购
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = item.item_id;
+                        itemStockoccupyDto.item_no = item.num;
+                        item.kitting_time = DateTime.Now;
+                        item.is_use = true;
+                        StartProcessing(item,icitemlist,returnlist,plan_date,sentrys,sklist,itemStockoccupyDto,bangid,input);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 针对缺料开始进行处理
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="plan_date"></param>
+        /// <param name="sentrys"></param>
+        /// <param name="sklist"></param>
+        /// <param name="itemStockoccupyDto"></param>
+        /// <param name="bangid"></param>
+        /// <param name="input"></param>
+        public void StartProcessing(BomChildExamineDto item, List<ic_item> icitemlist, List<BomChildExamineDto> returnlist, DateTime
+            ? plan_date, crm_seorderentry sentrys, List<ic_item_stockoccupy> sklist, ic_item_stockoccupy itemStockoccupyDto, long bangid, SeorderentryDto input)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            if (item.lack_qty > 0)
+            {
+                var cilList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).OrderBy(k => k.num).ToList();
+                //如果缺料,占用库存,然后走采购或自制
+                if (item.sqty > 0)
+                {
+                    itemStockoccupyDto.quantity = item.sqty;
+                    sklist.Add(itemStockoccupyDto);
+                }
+                item.use_qty = item.sqty;
+                if (item.erp_cls == 1)
+                {
+                    var ic_item = icitemlist.Find(s => s.Id == item.item_id);
+                    var mooccupylist = _morderAppService.CheckMorder(item.bom_number, item.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                    decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                    item.mo_qty = moo_qty;
+                    if (moo_qty == returnlist[0].lack_qty)
+                    {
+                        //在制完全足够
+                        item.lack_qty = 0;
+                        item.kitting_time = mooccupylist[0].moo_etime;
+                        item.stock_state = 1;
+                    }
+                    else
+                    {
+                        item.lack_qty -= moo_qty;
+                        item.kitting_time=DateTime.Now;
+                        //先计算末级数据的齐套时间。
+                        if (cilList.Count() > 0)
+                        {
+                            CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                            item.kitting_time = cilList.Max(s => s.kitting_time);
+                        }
+
+                        //走自制
+                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = item.bom_number,
+                            version = item.version,
+                            packages = (int)item.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        var ktime = item.kitting_time.Value.AddDays((double)Day);
+                        item.kitting_time = ktime > mooccupylist[0].moo_etime ? ktime : mooccupylist[0].moo_etime;
+                    }
+                }
+                else if (item.erp_cls == 3)
+                {
+                    //采购申请
+                    var SRMPRDto = CreateSRMPR(item, input.tenantId, input.factoryId, bangid, item.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                    item.kitting_time = SRMPRDto.lastStartTmie;
+                    SRMPRDtoList.Add(SRMPRDto);
+                }
+                else if (item.erp_cls == 2)
+                {
+                    //先计算末级数据的齐套时间。
+                    if (cilList.Count() > 0)
+                    {
+                        CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                        item.kitting_time = cilList.Max(s => s.kitting_time);
+                    }
+                    //1.先生成委外工单。
+                    var mesorder = CreateMesOOder(item, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                    item.kitting_time = mesorder.ooentry_etime;
+                    orderList.Add(mesorder);
+                }
+            }
+            else
+            {
+                //如果父级缺料,则本级等于父级缺料*本级使用数量
+                if (parent != null)
+                {
+                    item.use_qty = parent.lack_qty * item.qty;
+                    itemStockoccupyDto.quantity = item.use_qty;
+                }
+                sklist.Add(itemStockoccupyDto);
+            }
+        }
+
+
+        /// <summary>
+        /// 平铺计算物料情况
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="item"></param>
+        /// <param name="count"></param>
+        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item, decimal count)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            //当前物料总共需要数量
+            item.needCount = parent.needCount * item.qty;
+            /*//当前库存可以满足的数量
+            item.satisfyNum = item.sqty;
+            //总需要数量减去库存量,得出缺料数量
+            item.lack_qty = item.needCount - item.satisfyNum;
+            //如果不满足,计算子物料,或者计算替代料
+            if (item.lack_qty < 0)
+            {
+                //库存满足
+                item.stock_state = 1;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                item.stock_state = 0;
+            }*/
+        }
+
+        /// <summary>
+        /// 根据占用情况重新计算占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        public void RecalculationStock(BomChildExamineDto item, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist)
+        {
+            //再计算一边占用情况,这里根据父级产品额缺料量*当前子料的使用数量-子料库存量。得出当前子物料的缺料数量
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            decimal stockQty = sklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
+            item.sqty = item.sqty - stockQty;
+            item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+            item.lack_qty = item.lack_qty > 0 ? item.lack_qty : 0;
+            item.stock_state = item.lack_qty > 0 ? 0 : 1;
+        }
+
+        /// <summary>
+        /// 根据替代策略计算
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="sklist"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void CalcStrategy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, List<ic_item_stockoccupy> sklist, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            //提取群组关系
+            var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
+            List<BomChildExamineDto> select = new List<BomChildExamineDto>();
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            switch (item.substitute_strategy)
+            {
+                case 0://整批
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    //如果都需要采购的情况下,则默认使用优先级最高的
+                    WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 1://混用
+                    MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 2://整批加混用
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    if (select.Count() == 0)
+                    {
+                        //走混用
+                        MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        //走整批
+                        WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    break;
+            }
+        }
+        /// <summary>
+        /// 整批计算
+        /// </summary>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        public void WholeBatchCheck(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select)
+        {
+            for (int idx = 0; idx < 99; idx++)
+            {
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    //可制计算:需要对list进行可制计算,按主料来算辅料
+                    if (list.Where(s => s.stock_state != 1).Count() == 0)
+                    {
+                        //只满足充足或可制
+                        //无缺料情况
+                        select = list;
+                        select.ForEach(s => { s.is_use = true; });
+                        break;
+                    }
+                    idx++;
+                }
+                else
+                {
+                    idx = 99;
+                }
+            }
+        }
+        /// <summary>
+        /// 整批占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void WholeBatch(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            if (select.Count() == 0)
+            {
+                //如果为空,则默认使用优先级为0的集合作为替代关系
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                select.ForEach(s => { s.is_use = true; });
+            }
+            //占用库存
+            foreach (var slt in select)
+            {
+                ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                itemStockoccupyDto.bang_id = bangid;
+                itemStockoccupyDto.icitem_id = slt.item_id;
+                itemStockoccupyDto.item_no = slt.num;
+                slt.is_use = true;
+                StartProcessing(slt, icitemlist, returnlist, plan_date, sentrys, sklist, itemStockoccupyDto, bangid, input);
+            }
+
+        }
+
+        /// <summary>
+        /// 混用占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void MixedUse(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+
+            decimal parent_lack = 0;
+            if (parent != null)
+            {
+                parent_lack = parent.lack_qty;
+            }
+            for (int idx = 0; idx < 99; idx++)
+            {
+                if (parent_lack <= 0)
+                {
+                    break;
+                }
+
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    decimal minMake = 99999999;
+                    foreach (var hy in list)
+                    {
+                        //混用先使用掉当前要用的数量
+                        //得到库存最小数量,去占用,然后剩余的丢第二个循环里去占用。
+                        //获取物料详情
+                        var ic_item = icitemlist.Find(s => s.Id == hy.item_id);
+                        var mooccupylist = _morderAppService.CheckMorder(hy.bom_number, hy.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item, false).Result;
+                        decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                        decimal make = (hy.sqty + moo_qty) / hy.qty;
+                        if (Math.Floor(hy.qty) == hy.qty)
+                        {
+                            //如果物料的使用数量是小数,则按小数计算。
+                            make = Math.Floor(make);
+                        }
+                        if (minMake > make)
+                        {
+                            minMake = make;
+                        }
+                    }
+                    decimal use_p_num = 0;
+                    if (parent_lack > minMake) //20>10
+                    {
+                        use_p_num = minMake;
+                        parent_lack -= use_p_num;
+                    }
+                    else
+                    {
+                        use_p_num = parent_lack;
+                        parent_lack = 0;
+                    }
+                    //根据混用逻辑,去占用物料
+                    foreach (var zy in list)
+                    {
+                        zy.is_use = true;
+                        zy.kitting_time = DateTime.Now;
+                        if (parent_lack <= 0)
+                        {
+                            zy.stock_state = 1;
+                        }
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = zy.item_id;
+                        decimal moo_qty = use_p_num * zy.qty - zy.sqty;
+                        if (moo_qty > 0)
+                        {
+                            var ic_item = icitemlist.Find(s => s.Id == zy.item_id);
+                            var mooccupylist = _morderAppService.CheckMorder(zy.bom_number, moo_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                            itemStockoccupyDto.quantity = zy.sqty;
+                            zy.use_qty = zy.sqty;
+                            zy.mo_qty = moo_qty;
+                        }
+                        else {
+                            zy.use_qty = use_p_num * zy.qty;
+                            itemStockoccupyDto.quantity = zy.use_qty;
+                        }
+                        itemStockoccupyDto.item_no = zy.num;
+                        sklist.Add(itemStockoccupyDto);
+                    }
+                    idx++;
+                }
+            }
+            if (parent_lack > 0)
+            {
+                var select = new List<BomChildExamineDto>();
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                //对select执行采购
+                foreach (var sct in select)
+                {
+                    //找到当前物料的占用记录
+                    var itemSockoccupy = sklist.Where(s => s.icitem_id == sct.item_id).ToList();
+                    var num = parent_lack * sct.qty - itemSockoccupy.Sum(m => m.quantity);
+                    if (sct.erp_cls == 1)
+                    {
+                        //走自制
+                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = sct.bom_number,
+                            version = sct.version,
+                            packages = (int)sct.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        sct.kitting_time = sct.kitting_time.Value.AddDays((double)Day);
+                    }
+                    else if (sct.erp_cls == 3)
+                    {
+                        //采购申请
+                        var SRMPRDto = CreateSRMPR(sct, input.tenantId, input.factoryId, bangid, sct.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                        sct.kitting_time = SRMPRDto.lastStartTmie;
+                        SRMPRDtoList.Add(SRMPRDto);
+                    }
+                    else if (sct.erp_cls == 2)
+                    {
+                        //1.先生成委外工单。
+                        var mesorder = CreateMesOOder(sct, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                        sct.kitting_time = mesorder.ooentry_etime;
+                        orderList.Add(mesorder);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 可制占用计算---暂时未用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="kznun"></param>
+        public void Sockoccupy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, decimal kznun)
+        {
+            ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+            itemStockoccupyDto.bang_id = bangid;
+            if (item.stock_state == 1)
+            {
+                //成品库存占用
+                //slt.needCount
+                //可制物料占用
+                //slt.kz;如果是BOM,就展开BOM占用子物料
+                itemStockoccupyDto.icitem_id = item.item_id;
+                itemStockoccupyDto.quantity = item.needCount;
+            }
+            else if (item.stock_state == 2 || item.stock_state == 3)
+            {
+                itemStockoccupyDto.quantity = item.sqty;
+                var num = item.lack_qty;//可制满足的情况下,直接占用可制。
+                var sltChild = returnlist.Where(s => s.parent_id == item.id).ToList();
+                if (sltChild.Count() > 0)
+                {
+                    //有子集,则代表每条明细的库存加可制,才是父级的可制。
+                    foreach (var c in sltChild)
+                    {
+                        Sockoccupy(c, returnlist, bangid, num);
+                    }
+                }
+            }
+            //如果存在外购或者委外
+            else if (item.stock_state == 4 || item.stock_state == 5)
+            {
+                //根据最小颗粒度
+            }
+        }
+
+        /// <summary>
+        /// 计算物料是否缺料
+        /// </summary>
+        /// <param name="parent"></param>
+        /// <param name="bzlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sockoccupyList"></param>
+        public void calcTest2(BomChildExamineDto parent, List<BomChildExamineDto> bzlist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //从第二级开始循环
+            foreach (var item in bzlist)
+            {
+                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == 0).ToList();
+
+                //根据占用情况计算库存
+                Calczykc(item, parent, sockoccupyList);
+                //如果有子集,则丢入循环,判断下库存可制等信息。
+                calcTest2(item, childList, returnlist, sockoccupyList);
+            }
+        }
+
+        /// <summary>
+        /// 递归计算物料信息--暂未使用
+        /// </summary>
+        /// <param name="sublist"></param>
+        public void MaterialCalc(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            int maxIdx = sublist.Max(s => s.substitute_all_num);
+            for (int i = 0; i <= maxIdx; i++)
+            {
+                var group = sublist.Where(s => s.substitute_all_num == i).ToList();
+                // int boolCount = 0;//代表某一颗物料无需采购,可以自制,则集合+1。
+
+                //如果替代料库存不够,但是可制够,则也考虑使用优先级最高
+                foreach (var g in group)
+                {
+                    var parent = returnlist.Find(s => s.id == g.parent_id);
+                    //根据占用情况计算库存
+                    Calczykc(g, parent, sockoccupyList);
+                    /*if (g.stock_state != 1)
+                    {
+                        //判断此料是否BOM,如果是BOM,就考虑自制是否足够,此处递归检查子集
+                        var gChildList = returnlist.Where(s => s.parent_id == g.id).ToList();
+                        if (gChildList.Count > 0)
+                        {
+                            calcTest2(g, gChildList, returnlist, sockoccupyList);
+                            //如果是自制,则考虑自制够不够
+                            if (g.erp_cls == 1)
+                            {
+                                foreach (var cc in gChildList)
+                                {
+                                    //如果子物料是BOM,则当前物料的可制数量应该是子物料的库存加子物料的可制除以子物料的使用量
+                                    if (returnlist.Where(s => s.parent_id == cc.id).Count() > 0)
+                                    {
+                                        cc.kz = Math.Floor((cc.sqty + cc.kz) / g.qty);
+                                    }
+                                }
+                                g.kz = gChildList.Min(s => s.kz);//得到最小可制数量。
+                                
+                                //todo:如果是群组替代,可制数量应该跟随着主料来,不应该受限于最小可制单元。
+                                g.stock_state = gChildList.Max(s => s.stock_state);
+                                if (g.lack_qty <= g.kz)
+                                {
+                                    g.stock_state = 2;
+                                    boolCount++;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            g.kz = Math.Floor(g.sqty / g.qty);//自己不是BOM的情况下,算一下自己可制父级可以制造多少个,这个可制只是基于父级BOM才用来运算。
+                            //todo:申老师说,如果是苏州工厂,原材料有可能也是自制的。
+                            //所以这里在计算时,还可以直接拿缺料数量,去丢给苏州计算方法,得出原材料的库存加可制。
+                        }
+                    }
+                    else
+                    {
+                        boolCount++;
+                    }*/
+                }
+
+                /*if (boolCount == group.Count())
+                {
+                    //如果检查集合满足条数与群组里的物料条数相同,则代表这个群组的数量是满足的。
+                    group.ForEach(s =>
+                    {
+                        s.is_show = true;
+                    });
+                    break;//如果已经找到合适的替代群组关系,并且都不需要采购,则直接不继续检查了。
+                }*/
+            }
+        }
+
+        /// <summary>
+        /// 根据每个物料来实时计算占用情况
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sockoccupyList"></param>
+        public void Calczykc(BomChildExamineDto item, BomChildExamineDto parent, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //找到当前物料的占用记录
+            var itemSockoccupy = sockoccupyList.Where(s => s.icitem_id == item.item_id).ToList();
+            //计算库存减去占用
+            item.sqty -= itemSockoccupy.Sum(s => s.quantity);
+            //如果库存
+            item.sqty = item.sqty < 0 ? 0 : item.sqty;
+            if (parent.stock_state == 1 || parent.stock_state == -1)
+            {
+                item.stock_state = parent.stock_state;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                //判断缺料数量
+                item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+                item.lack_qty = item.lack_qty < 0 ? 0 : item.lack_qty;
+                //判断状态
+                item.stock_state = item.lack_qty > 0 ? 0 : 1;
+            }
+        }

+ 5 - 0
MicroServices/Business/Business.Application.Contracts/ResourceExamineManagement/Dto/BomChildExamineDto.cs

@@ -59,6 +59,11 @@ namespace Business.ResourceExamineManagement.Dto
         /// </summary>
         public string num { get; set; }
 
+        /// <summary>
+        /// 供排序使用
+        /// </summary>
+        public long num_order { get; set; }
+
         /// <summary>
         /// 类型 0标准件,1替代件
         /// </summary>

+ 869 - 0
MicroServices/Business/Business.Application/ResourceExamineManagement/CalcBomViewAppService.cs

@@ -0,0 +1,869 @@
+using Business.Core.MongoDBHelper;
+using Business.ResourceExamineManagement.Dto;
+using Bussiness.Model.MES.IC;
+using Bussiness.Model.Production;
+using Bussiness.Model.Sale;
+using Bussiness.Model.SRM;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace Business.ResourceExamineManagement
+{
+    public class CalcBomViewAppService : ApplicationService
+    {
+        /// <summary>
+        /// 资源检查入参
+        /// </summary>
+        public SeorderentryDto param = new SeorderentryDto();
+
+        public List<ic_plan> planList { get; set; }
+
+        public List<ICItemLeadTimeDto> leadTimeList = new List<ICItemLeadTimeDto>();
+        public List<ic_item_pur> supplierList = new List<ic_item_pur>();
+
+        public List<SRMPRDto> SRMPRDtoList = new List<SRMPRDto>();
+        public List<mes_oorder> orderList = new List<mes_oorder>();
+
+        public List<mes_morder> mordersList = new List<mes_morder>();
+        public List<mes_moentry> moentriesList = new List<mes_moentry>();
+        public List<mes_mooccupy> mooccupyAllList = new List<mes_mooccupy>();
+
+        /// <summary>
+        /// 工单App
+        /// </summary>
+        private readonly MorderAppService _morderAppService;
+
+        /// <summary>
+        /// 产能检查
+        /// </summary>
+        private readonly ProductExamineAppService _productExamineAppService;
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="morderAppService"></param>
+        public CalcBomViewAppService(MorderAppService morderAppService,
+            ProductExamineAppService productExamineAppService)
+        {
+            _morderAppService = morderAppService;
+            _productExamineAppService = productExamineAppService;
+        }
+
+
+        /// <summary>
+        /// 计算物料库存量
+        /// </summary>
+        /// <param name="returnlist"></param>
+        public void BomStock(List<BomChildExamineDto> returnlist, List<ic_item_stock> _ic_item_stock)
+        {
+            returnlist = returnlist.OrderBy(s => s.num_order).ToList();
+            //获取当前工厂下物料库存数据
+            List<long> icitemIds = returnlist.Select(c => c.item_id).ToList();
+            var stocklist = _ic_item_stock.Where(p => p.factory_id == param.factoryId && icitemIds.Contains(p.icitem_id)).ToList();
+            //计算剩余库存
+            foreach (var item in returnlist)
+            {
+                if (item.erp_cls == 4)//虚拟件不计算
+                {
+                    continue;
+                }
+                //非虚拟件
+                //当前物料的库存数量
+                decimal stockQty = stocklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.sqty.GetValueOrDefault());
+                item.sqty = stockQty;
+            }
+        }
+
+
+        /// <summary>
+        /// Bom平铺物料情况计算
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="count"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void CalcView(List<BomChildExamineDto> returnlist, long bangid, decimal count, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item_stockoccupy> sklist, crm_seorderentry sentrys, List<ic_item> icitemlist)
+        {
+            //第一级
+            returnlist = returnlist.OrderBy(s => s.num_order).ToList();
+            var level1Dto = returnlist[0];
+            //第二级
+            var childList = returnlist.Where(s => s.parent_id == level1Dto.id && s.type == 0).OrderBy(s => s.num_order).ToList();
+
+            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
+            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
+            List<long> calcIds = new List<long>();
+            //先处理下最顶级的产品需要数量
+
+            level1Dto.needCount = level1Dto.qty * count;
+            level1Dto.lack_qty = level1Dto.needCount - level1Dto.sqty;
+            //平铺需要数量
+            CaclMaterialShortage(returnlist);
+
+            Mes_MorderDto mes_MorderDto = new Mes_MorderDto();
+            if (level1Dto.lack_qty > 0)
+            {
+                //获取物料详情
+                var ic_item = icitemlist.Find(s => s.Id == level1Dto.item_id);
+                var mooccupylist = _morderAppService.CheckMorder(level1Dto.bom_number, level1Dto.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+
+                if (mooccupylist.Any())
+                {
+                    mooccupyAllList.AddRange(mooccupylist);
+                }
+
+                decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                level1Dto.mo_qty = moo_qty;
+
+                if (moo_qty == level1Dto.lack_qty)
+                {
+                    //在制完全足够
+                    level1Dto.lack_qty = 0;
+                    level1Dto.satisfy_time = mooccupylist[0].moo_etime;
+                    level1Dto.stock_state = 1;
+                    return;
+                }
+                else
+                {
+                    //占用不够,占用后减少缺料数量
+                    level1Dto.lack_qty -= moo_qty;
+                    //先设定在制的齐套时间
+                    //level1Dto.satisfy_time = mooccupylist[0]?.moo_etime;
+                    level1Dto.stock_state = 0;
+                    //生成主工单
+                    GenerateMorderDto generateMorderDto = new GenerateMorderDto()
+                    {
+                        seorderentry = sentrys,
+                        ic_Item = ic_item,
+                        BomNumber = level1Dto.bom_number,
+                        version = level1Dto.version,
+                        number = level1Dto.item_number,
+                        Quantity = level1Dto.lack_qty,
+                        morder_type = "销售工单",
+                        work_order_type = "常规工单",
+                        morder_state = "初始",
+
+                    };
+                    //生成主工单
+                    mes_MorderDto = _morderAppService.GenerateMorder(generateMorderDto);
+                }
+            }
+            else
+            {
+                level1Dto.satisfy_time = DateTime.Now;
+                level1Dto.stock_state = 1;
+                return;
+            }
+
+            //这是从上往下展开计算缺料和可制
+            CaleLackItem(level1Dto, childList, returnlist, sklist);
+            //level1Dto.kz = childList.Min(s => s.kz);//得到最小可制数量。
+            //再加个循环,来根据替代关系里的检查结果,根据规则明确使用和生成占用关系。
+            CalcIcitem(childList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+            level1Dto.kitting_time = childList.Max(s => s.kitting_time);
+            //这里更新产品得满足时间。
+            if (mes_MorderDto != null)
+            {
+                //主工单最后计算满足日期
+                var mes_Morders = mes_MorderDto.mes_Morders.Where(x => x.parent_id == null).FirstOrDefault();
+                if (mes_Morders != null)
+                {
+                    if (!string.IsNullOrEmpty(mes_Morders.bom_number))
+                    {
+                        //var ProductiveDate = ProductiveExamine(mes_Morders.bom_number, level1Dto.version, (int)mes_Morders.morder_production_number.Value);
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = mes_Morders.bom_number,
+                            version = level1Dto.version,
+                            packages = (int)mes_Morders.morder_production_number.Value,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var plan = planList.Find(x => x.icitem_id == level1Dto.item_id);
+                        var ProductiveDate = _productExamineAppService.ProductiveExamine(prodExamine);
+                        var Day = ProductiveDate.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        mes_Morders.moentry_sys_stime = level1Dto.kitting_time.Value.AddDays(1);//数据齐套完成后隔天开始生产;
+                        //结束日期=开始时间+生产时长+自检提前期+入库提前期+发运提前期;
+                        var LeadTime = 0.00m;
+                        if (plan != null)
+                        {
+                            LeadTime = Day + plan.self_inspection_date.Value + plan.Shipping_date.Value + plan.Warehousing_date.Value;
+                        }
+                        else
+                        {
+                            LeadTime = Day;
+                        }
+                        mes_Morders.moentry_sys_etime = mes_Morders.moentry_sys_stime.Value.AddDays((double)Day);
+                        mes_Morders.morder_need_time = ProductiveDate.Result;
+                        //满足资源检查的时间需加上提前期
+                        level1Dto.satisfy_time = mes_Morders.moentry_sys_stime.Value.AddDays((double)LeadTime);
+                    }
+                    //批量保存 后期考虑子工单
+                    mordersList.AddRange(mes_MorderDto.mes_Morders);
+                    moentriesList.AddRange(mes_MorderDto.mes_Moentries);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 平铺计算物料情况
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="item"></param>
+        /// <param name="count"></param>
+        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist)
+        {
+            foreach (var item in returnlist)
+            {
+                if (item.level == 1)
+                {
+                    continue;
+                }
+                //循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
+                var parent = returnlist.Find(s => s.id == item.parent_id);
+                //当前物料总共需要数量
+                item.needCount = parent.needCount * item.qty;
+            }
+        }
+
+        /// <summary>
+        /// 计算物料是否缺料
+        /// </summary>
+        /// <param name="parent"></param>
+        /// <param name="bzlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sockoccupyList"></param>
+        public void CaleLackItem(BomChildExamineDto parent, List<BomChildExamineDto> bzlist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //从第二级开始循环
+            foreach (var item in bzlist)
+            {
+                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == 0).ToList();
+
+                //根据占用情况计算库存
+                Calczykc(item, parent, sockoccupyList);
+                //如果有子集,则丢入循环,判断下库存可制等信息。
+                CaleLackItem(item, childList, returnlist, sockoccupyList);
+            }
+        }
+
+        /// <summary>
+        /// 根据每个物料来实时计算占用情况
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sockoccupyList"></param>
+        public void Calczykc(BomChildExamineDto item, BomChildExamineDto parent, List<ic_item_stockoccupy> sockoccupyList)
+        {
+            //找到当前物料的占用记录
+            var itemSockoccupy = sockoccupyList.Where(s => s.icitem_id == item.item_id).ToList();
+            //计算库存减去占用
+            item.sqty -= itemSockoccupy.Sum(s => s.quantity);
+            //如果库存
+            item.sqty = item.sqty < 0 ? 0 : item.sqty;
+            if (parent.stock_state == 1 || parent.stock_state == -1)
+            {
+                item.stock_state = parent.stock_state;
+                item.lack_qty = 0;
+            }
+            else
+            {
+                //判断缺料数量
+                item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+                item.lack_qty = item.lack_qty < 0 ? 0 : item.lack_qty;
+                //判断状态
+                item.stock_state = item.lack_qty > 0 ? 0 : 1;
+            }
+        }
+
+        /// <summary>
+        /// 循环计算物料情况
+        /// </summary>
+        /// <param name="childList"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="orderid"></param>
+        /// <param name="input"></param>
+        /// <param name="sklist"></param>
+        /// <param name="plan_date"></param>
+        public void CalcIcitem(List<BomChildExamineDto> childList, List<BomChildExamineDto> returnlist, long bangid, SeorderentryDto input, List<ic_item_stockoccupy> sklist, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            foreach (var item in childList)
+            {
+                var parent = returnlist.Find(s => s.id == item.parent_id);
+                if (parent.stock_state == 0)
+                {
+                    if (item.haveicsubs == 1)
+                    {
+                        //如果有替代关系,根据群组来明确使用哪个群组的替代料。按整批和混用逻辑来算
+                        // 如果有群组替代,就移除掉被检查过的记录 item.icitem_ids
+                        CalcStrategy(item, returnlist, bangid, sklist, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        Calczykc(item, parent, sklist);
+
+                        //直接占用库存,缺料就生成采购
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = item.item_id;
+                        itemStockoccupyDto.item_no = item.num;
+                        item.kitting_time = DateTime.Now;
+                        item.is_use = true;
+                        StartProcessing(item, icitemlist, returnlist, plan_date, sentrys, sklist, itemStockoccupyDto, bangid, input);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// 针对缺料开始进行处理
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="plan_date"></param>
+        /// <param name="sentrys"></param>
+        /// <param name="sklist"></param>
+        /// <param name="itemStockoccupyDto"></param>
+        /// <param name="bangid"></param>
+        /// <param name="input"></param>
+        public void StartProcessing(BomChildExamineDto item, List<ic_item> icitemlist, List<BomChildExamineDto> returnlist, DateTime
+            ? plan_date, crm_seorderentry sentrys, List<ic_item_stockoccupy> sklist, ic_item_stockoccupy itemStockoccupyDto, long bangid, SeorderentryDto input)
+        {
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            if (item.lack_qty > 0)
+            {
+                var cilList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).OrderBy(k => k.num_order).ToList();
+                //如果缺料,占用库存,然后走采购或自制
+                if (item.sqty > 0)
+                {
+                    itemStockoccupyDto.quantity = item.sqty;
+                    sklist.Add(itemStockoccupyDto);
+                }
+                item.use_qty = item.sqty;
+                if (item.erp_cls == 1)
+                {
+                    /*var ic_item = icitemlist.Find(s => s.Id == item.item_id);
+                    var mooccupylist = _morderAppService.CheckMorder(item.bom_number, item.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                    decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                    item.mo_qty = moo_qty;*/
+                    decimal moo_qty = 0;
+                    if (moo_qty == returnlist[0].lack_qty)
+                    {
+                        //在制完全足够
+                        item.lack_qty = 0;
+                        //item.kitting_time = mooccupylist[0].moo_etime;
+                        item.kitting_time = DateTime.Now;
+                        item.stock_state = 1;
+                    }
+                    else
+                    {
+                        item.lack_qty -= moo_qty;
+                        item.kitting_time = DateTime.Now;
+                        //先计算末级数据的齐套时间。
+                        if (cilList.Count() > 0)
+                        {
+                            CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                            item.kitting_time = cilList.Max(s => s.kitting_time);
+                        }
+
+                        //走自制
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = item.bom_number,
+                            version = item.version,
+                            packages = (int)item.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        var ktime = item.kitting_time.Value.AddDays((double)Day);
+                        //item.kitting_time = ktime > mooccupylist[0].moo_etime ? ktime : mooccupylist[0].moo_etime;
+                        item.kitting_time = ktime;
+                    }
+                }
+                else if (item.erp_cls == 3)
+                {
+                    //采购申请
+                    var SRMPRDto = CreateSRMPR(item, input.tenantId, input.factoryId, bangid, item.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                    item.kitting_time = SRMPRDto.lastStartTmie;
+                    SRMPRDtoList.Add(SRMPRDto);
+                }
+                else if (item.erp_cls == 2)
+                {
+                    //先计算末级数据的齐套时间。
+                    if (cilList.Count() > 0)
+                    {
+                        CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
+                        item.kitting_time = cilList.Max(s => s.kitting_time);
+                    }
+                    //1.先生成委外工单。
+                    var mesorder = CreateMesOOder(item, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                    item.kitting_time = mesorder.ooentry_etime;
+                    orderList.Add(mesorder);
+                }
+            }
+            else
+            {
+                //如果父级缺料,则本级等于父级缺料*本级使用数量
+                if (parent != null)
+                {
+                    item.use_qty = parent.lack_qty * item.qty;
+                    itemStockoccupyDto.quantity = item.use_qty;
+                }
+                sklist.Add(itemStockoccupyDto);
+            }
+        }
+
+        /// <summary>
+        /// 根据替代策略计算
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="sklist"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void CalcStrategy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, List<ic_item_stockoccupy> sklist, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            //提取群组关系
+            var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
+            List<BomChildExamineDto> select = new List<BomChildExamineDto>();
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            switch (item.substitute_strategy)
+            {
+                case 0://整批
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    //如果都需要采购的情况下,则默认使用优先级最高的
+                    WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 1://混用
+                    MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    break;
+                case 2://整批加混用
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    if (select.Count() == 0)
+                    {
+                        //走混用
+                        MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    else
+                    {
+                        //走整批
+                        WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
+                    }
+                    break;
+            }
+        }
+        /// <summary>
+        /// 整批计算
+        /// </summary>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        public void WholeBatchCheck(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select)
+        {
+            for (int idx = 0; idx < 99; idx++)
+            {
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    //可制计算:需要对list进行可制计算,按主料来算辅料
+                    if (list.Where(s => s.stock_state != 1).Count() == 0)
+                    {
+                        //只满足充足或可制
+                        //无缺料情况
+                        select = list;
+                        select.ForEach(s => { s.is_use = true; });
+                        break;
+                    }
+                    idx++;
+                }
+                else
+                {
+                    idx = 99;
+                }
+            }
+        }
+        /// <summary>
+        /// 整批占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="select"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void WholeBatch(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+            if (select.Count() == 0)
+            {
+                //如果为空,则默认使用优先级为0的集合作为替代关系
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                select.ForEach(s => { s.is_use = true; });
+            }
+            //占用库存
+            foreach (var slt in select)
+            {
+                ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                itemStockoccupyDto.bang_id = bangid;
+                itemStockoccupyDto.icitem_id = slt.item_id;
+                itemStockoccupyDto.item_no = slt.num;
+                slt.is_use = true;
+                StartProcessing(slt, icitemlist, returnlist, plan_date, sentrys, sklist, itemStockoccupyDto, bangid, input);
+            }
+
+        }
+
+        /// <summary>
+        /// 混用占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="sublist"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        /// <param name="bangid"></param>
+        /// <param name="parent"></param>
+        /// <param name="input"></param>
+        /// <param name="plan_date"></param>
+        public void MixedUse(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
+            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
+        {
+
+            decimal parent_lack = 0;
+            if (parent != null)
+            {
+                parent_lack = parent.lack_qty;
+            }
+            for (int idx = 0; idx < 99; idx++)
+            {
+                if (parent_lack <= 0)
+                {
+                    break;
+                }
+
+                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                if (list.Any())
+                {
+                    foreach (var s in list)
+                    {
+                        RecalculationStock(s, returnlist, sklist);
+                    }
+                    decimal minMake = 99999999;
+                    foreach (var hy in list)
+                    {
+                        //混用先使用掉当前要用的数量
+                        //得到库存最小数量,去占用,然后剩余的丢第二个循环里去占用。
+                        //获取物料详情
+                        /*var ic_item = icitemlist.Find(s => s.Id == hy.item_id);
+                        var mooccupylist = _morderAppService.CheckMorder(hy.bom_number, hy.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item, false).Result;
+                        decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
+                        decimal make = (hy.sqty + moo_qty) / hy.qty;
+                        if (Math.Floor(hy.qty) == hy.qty)
+                        {
+                            //如果物料的使用数量是小数,则按小数计算。
+                            make = Math.Floor(make);
+                        }
+                        if (minMake > make)
+                        {
+                            minMake = make;
+                        }*/
+                        //先去掉上面的在制
+                        decimal make = hy.sqty / hy.qty;
+                        if (Math.Floor(hy.qty) == hy.qty)
+                        {
+                            //如果物料的使用数量是小数,则按小数计算。
+                            make = Math.Floor(make);
+                        }
+                        if (minMake > make)
+                        {
+                            minMake = make;
+                        }
+
+                    }
+                    decimal use_p_num = 0;
+                    if (parent_lack > minMake) //20>10
+                    {
+                        use_p_num = minMake;
+                        parent_lack -= use_p_num;
+                    }
+                    else
+                    {
+                        use_p_num = parent_lack;
+                        parent_lack = 0;
+                    }
+                    //根据混用逻辑,去占用物料
+                    foreach (var zy in list)
+                    {
+                        zy.is_use = true;
+                        zy.kitting_time = DateTime.Now;
+                        if (parent_lack <= 0)
+                        {
+                            zy.stock_state = 1;
+                        }
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = zy.item_id;
+                        /*decimal moo_qty = use_p_num * zy.qty - zy.sqty;
+                        if (moo_qty > 0)
+                        {
+                            var ic_item = icitemlist.Find(s => s.Id == zy.item_id);
+                            var mooccupylist = _morderAppService.CheckMorder(zy.bom_number, moo_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
+                            itemStockoccupyDto.quantity = zy.sqty;
+                            zy.use_qty = zy.sqty;
+                            zy.mo_qty = moo_qty;
+                        }
+                        else
+                        {
+                            zy.use_qty = use_p_num * zy.qty;
+                            itemStockoccupyDto.quantity = zy.use_qty;
+                        }*/
+                        //先去掉上面的在制逻辑
+                        zy.use_qty = use_p_num * zy.qty;
+                        itemStockoccupyDto.quantity = zy.use_qty;
+                        itemStockoccupyDto.item_no = zy.num;
+                        sklist.Add(itemStockoccupyDto);
+                    }
+                    idx++;
+                }
+            }
+            if (parent_lack > 0)
+            {
+                var select = new List<BomChildExamineDto>();
+                if (item.substitute_mode == 0)
+                {
+                    //替代
+                    select = sublist.Where(s => s.type == 0).ToList();
+                }
+                else
+                {
+                    //取代
+                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
+                }
+                //对select执行采购
+                foreach (var sct in select)
+                {
+                    //找到当前物料的占用记录
+                    var itemSockoccupy = sklist.Where(s => s.icitem_id == sct.item_id).ToList();
+                    var num = parent_lack * sct.qty - itemSockoccupy.Sum(m => m.quantity);
+                    if (sct.erp_cls == 1)
+                    {
+                        //走自制
+                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
+                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
+                        {
+                            bom_number = sct.bom_number,
+                            version = sct.version,
+                            packages = (int)sct.lack_qty,
+                            tenantId = param.tenantId,
+                            factoryId = param.factoryId
+
+                        };
+                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
+                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
+                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
+                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
+                        sct.kitting_time = sct.kitting_time.Value.AddDays((double)Day);
+                    }
+                    else if (sct.erp_cls == 3)
+                    {
+                        //采购申请
+                        var SRMPRDto = CreateSRMPR(sct, input.tenantId, input.factoryId, bangid, sct.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
+                        sct.kitting_time = SRMPRDto.lastStartTmie;
+                        SRMPRDtoList.Add(SRMPRDto);
+                    }
+                    else if (sct.erp_cls == 2)
+                    {
+                        //1.先生成委外工单。
+                        var mesorder = CreateMesOOder(sct, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
+                        sct.kitting_time = mesorder.ooentry_etime;
+                        orderList.Add(mesorder);
+                    }
+                }
+            }
+        }
+
+
+
+        /// <summary>
+        /// 根据占用情况重新计算占用
+        /// </summary>
+        /// <param name="item"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="sklist"></param>
+        public void RecalculationStock(BomChildExamineDto item, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist)
+        {
+            //再计算一边占用情况,这里根据父级产品额缺料量*当前子料的使用数量-子料库存量。得出当前子物料的缺料数量
+            var parent = returnlist.Find(s => s.id == item.parent_id);
+            decimal stockQty = sklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
+            item.sqty = item.sqty - stockQty;
+            item.lack_qty = parent.lack_qty * item.qty - item.sqty;
+            item.lack_qty = item.lack_qty > 0 ? item.lack_qty : 0;
+            item.stock_state = item.lack_qty > 0 ? 0 : 1;
+        }
+
+
+
+
+
+
+
+
+
+        /// <summary>
+        /// 生成采购申请单,颗粒度是一个物料一个单,没必要弄列表
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="factoryid"></param>
+        /// <param name="orderType">2委外采购申请单,3采购申请单</param>
+        private SRMPRDto CreateSRMPR(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, int orderType, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, List<ic_plan> planList, DateTime deliveryDate)
+        {
+            SRMPRDto sRMPR = new SRMPRDto();
+            srm_pr_main srm_Pr = new srm_pr_main();
+            var leadTime = iCItemLeadTimes.Find(x => x.item_id == returnlist.item_id);
+            var supplier = supplierList.Find(x => x.icitem_id == returnlist.item_id);//默认取第一个供应商
+            var plan = planList.Find(x => x.icitem_id == returnlist.item_id);
+            if (leadTime == null || supplier == null || plan == null)
+            {
+                sRMPR.srm_Pr_Main = null;
+                sRMPR.lastStartTmie = deliveryDate.AddDays(7 * -1);//减去提前期
+                return sRMPR;
+                //throw new NotImplementedException("未找到物料ic_factory_details或ic_item_pur或ic_plan信息!");
+            }
+
+            srm_Pr.GenerateNewId();
+            srm_Pr.pr_billno = getOrderNum("PR");//pr单号
+            srm_Pr.pr_mono = "";//关联工单号
+            srm_Pr.entity_id = 1;//工单行号
+            srm_Pr.pr_purchaseid = supplier.supplier_id;//供应商id  
+            srm_Pr.pr_purchasenumber = supplier.supplier_number;//供应商编码
+            srm_Pr.pr_purchasename = supplier.supplier_name;//供应商名称
+            srm_Pr.pr_purchaser = supplier.purcher;//采购员
+            srm_Pr.pr_purchaser_num = "";//采购员工号(采购信息表)
+            srm_Pr.pr_rqty = returnlist.lack_qty;//需求数量
+            srm_Pr.pr_aqty = returnlist.lack_qty;//申请数量
+            srm_Pr.pr_sqty = returnlist.lack_qty;//建议数量
+            srm_Pr.icitem_id = returnlist.item_id;//物料id
+            srm_Pr.icitem_name = returnlist.item_name;//物料名称
+            srm_Pr.pr_order_type = 1;//单据类型
+            srm_Pr.pr_ssend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//系统建议下单日期
+            srm_Pr.pr_sarrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//系统建议到达日期(建议到货日期)
+            srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+            srm_Pr.pr_parrive_date = deliveryDate.AddDays((double)leadTime.transportation_leadtime * -1);//计划到达日期
+            srm_Pr.pr_psend_date = deliveryDate.AddDays((double)leadTime.order_leadtime * -1);//计划下单日期
+            srm_Pr.pr_sysprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//系统价格(含税)
+            srm_Pr.pr_orderprice = returnlist.lack_qty * supplier.netpurchase_price * (1 + supplier.taxrate);//订单价格(含税)
+            srm_Pr.pr_price = supplier.netpurchase_price;//采购净价(不含税)
+            srm_Pr.pr_rate = supplier.taxrate;//税率
+            srm_Pr.pr_unit = returnlist.unit;//单位
+            srm_Pr.state = 1;//状态
+            srm_Pr.old_apply_aqty = 0;//已申请数量
+            srm_Pr.pr_type = orderType;//申请类型
+            srm_Pr.currencytype = supplier.currency_type;//币种
+            srm_Pr.secInv_ratio = plan.secinv_ratio;//安全库存触发采购比例
+            srm_Pr.tenant_id = tenantId;
+            srm_Pr.factory_id = factoryid;
+            srm_Pr.bang_id = bangId;
+            //_srm_pr_main.InsertOne(srm_Pr);
+            decimal? totalLeadTime = leadTime.transportation_leadtime + leadTime.stock_leadtime + leadTime.production_leadtime + leadTime.order_leadtime;
+
+            sRMPR.srm_Pr_Main = srm_Pr;
+            sRMPR.lastStartTmie = deliveryDate.AddDays((double)totalLeadTime * -1);//减去提前期
+            return sRMPR;
+        }
+
+        // 生成订单编号 字母+年月日+8位随机数+时间戳
+        private string getOrderNum(string preCode)
+        {
+            string Dates = DateTime.Now.ToString("yyyyMMdd");//获取当前时间
+            Random Rdm = new Random(Guid.NewGuid().GetHashCode());//随机数
+            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);//时间戳
+            string newts = Convert.ToInt64(ts.TotalMilliseconds).ToString();//时间戳          
+            string new_orderNum = preCode + Dates + Rdm.Next(0, 100000000) + newts;
+            return new_orderNum;
+        }
+
+        /// <summary>
+        /// 生成委外工单
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="factoryid"></param>
+        private mes_oorder CreateMesOOder(BomChildExamineDto returnlist, long tenantId, long factoryid, long bangId, List<ICItemLeadTimeDto> iCItemLeadTimes, List<ic_item_pur> supplierList, DateTime deliveryDate)
+        {
+            mes_oorder oOrder = new mes_oorder();
+            oOrder.GenerateNewId();
+            oOrder.oorder_no = getOrderNum("WW");//生产工单编号
+            oOrder.oorder_type = "委外工单";//生产工单类型
+            oOrder.oorder_date = DateTime.Now;//委外订单日期
+            oOrder.oorder_state = "已提交";//订单状态
+            oOrder.ooentry_prd = 10000;//生产组织
+            oOrder.ooentry_prdname = "1000";//生产组织名称
+            oOrder.ooentry_wrkc = 10000;//工作中心id
+            oOrder.ooentry_wrkcname = "10001";//工作中心名称
+            oOrder.planner_num = "wwww";//计划员工号
+            oOrder.planner_name = "qqq";//计划员名称
+            oOrder.ooentry_stime = DateTime.Now;//计划开工日期
+            oOrder.ooentry_etime = DateTime.Now;//计划完工日期
+            oOrder.product_code = "产品代码";//产品代码
+            oOrder.ffms_number = "1000";//fms旧料号
+            oOrder.product_name = "test";//产品名称
+            oOrder.specification_model = returnlist.model;//规格型号
+            oOrder.bom_number = "";//bom编码
+            oOrder.unit = returnlist.unit;//单位
+            oOrder.morder_progress = "";//工单进度
+            oOrder.morder_production_number = returnlist.lack_qty;//工单生产数量(计划数量)
+            oOrder.need_number = returnlist.lack_qty;//需求数量
+            oOrder.remaining_number = returnlist.lack_qty;//剩余可用数量
+            oOrder.work_number = 0;//报工数量
+            oOrder.inspection_number = 0;//报检数量
+            oOrder.qualified_number = 0;//合格数量
+            oOrder.inventory_number = 0;//入库数量
+            oOrder.notice_qty = 0;//已开通知单数量
+            oOrder.moentry_on = 1;//启动状态
+            //oOrder.start_time = DateTime.Now;//开始时间
+            //oOrder.pause_time = DateTime.Now;//最近暂停时间
+            //oOrder.restart_time = DateTime.Now;//最近重启时间
+            oOrder.project_name = returnlist.item_name;//项目名称
+            oOrder.sent_status = 1;//发料状态 1-待发料  2-已发料
+            oOrder.production_unit = returnlist.unit;//加工单位
+            oOrder.production_unit_code = "";//加工单位编码
+            oOrder.need_icitem_status = 1;//所需物料是否充足  1-充足 0-缺料
+            oOrder.tenant_id = tenantId;
+            oOrder.factory_id = factoryid;
+            oOrder.bang_id = bangId;
+            return oOrder;
+            //_mes_oorder.InsertOne(oOrder);
+        }
+
+    }
+}

+ 0 - 4
MicroServices/Business/Business.Application/ResourceExamineManagement/MorderAppService.cs

@@ -292,10 +292,6 @@ namespace Business.ResourceExamineManagement
                 }
 
             }
-            if (flag && mes_Mooccupies.Count > 0)
-            {
-                await _mes_mooccupy.InsertMany(mes_Mooccupies);
-            }
             #region 注释
             //  if (morderDataList.Count > 0)
             //  {

+ 313 - 0
MicroServices/Business/Business.Application/ResourceExamineManagement/PretreatmentAppService.cs

@@ -0,0 +1,313 @@
+using Business.Core.MongoDBHelper;
+using Business.Core.Utilities;
+using Business.ResourceExamineManagement.Dto;
+using Bussiness.Model.MES.IC;
+using Bussiness.Model.Production;
+using SixLabors.ImageSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Volo.Abp.Application.Services;
+
+namespace Business.ResourceExamineManagement
+{
+    public class PretreatmentAppService : ApplicationService
+    {
+        SnowFlake help = new SnowFlake();
+
+        //构造函数
+        public PretreatmentAppService() {
+        }
+
+        /// <summary>
+        /// BOM预处理
+        /// </summary>
+        /// <param name="orderid"></param>
+        /// <param name="BomId"></param>
+        /// <param name="Quantity"></param>
+        public List<BomChildExamineDto> BomPretreatment(long? BomId, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist)
+        {
+            if (BomId == null)
+            {
+                //throw new bu
+            }
+            List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+
+            var bom = bomlist.Find(s => s.Id == BomId);
+            if (bom == null)
+            {
+                return returnlist;
+            }
+
+            var dto = new BomChildExamineDto();
+            dto.item_id = bom.icitem_id;
+            dto.bom_id = BomId.Value;
+            dto.bom_number = bom.bom_number;
+            dto.level = 1;
+            dto.id = help.NextId();
+            dto.parent_id = help.NextId();
+            dto.qty = 1;
+            dto.num = "1";
+            dto.num_order = 1;
+            dto.isbom = 1;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            int type = 0;
+            GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            return returnlist;
+        }
+
+        /// <summary>
+        /// BOM预处理层级组装
+        /// </summary>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="dto"></param>
+        /// <param name="returnlist"></param>
+        public void GetBomList(List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, BomChildExamineDto dto, List<BomChildExamineDto> returnlist, int type)
+        {
+            int level = dto.level + 1;//初始化定义level层级
+
+            var bom = bomlist.Where(s => s.Id == dto.bom_id).FirstOrDefault();
+            ic_item item = new ic_item();
+            if (bom != null)
+            {
+                item = icitemlist.Where(a => a.Id == bom.icitem_id).FirstOrDefault();
+            }
+            else
+            {
+                item = icitemlist.Where(a => a.Id == dto.item_id).FirstOrDefault();
+            }
+            if (item == null)
+            {
+                return;
+            }
+            dto.item_id = item.Id;
+            dto.item_name = bom.item_name;
+            dto.item_code = bom.item_number;
+            dto.model = item.model;
+            dto.unit = bom.unit;
+            dto.erp_cls = item.erp_cls;
+            dto.erp_cls_name = item.erp_cls_name;
+            dto.type = type;
+            dto.item_number = item.number;
+
+            //var bdto = ObjectMapper.Map<ic_bom,BomChildExamineDto>(bom);
+            returnlist.Add(dto);
+            var childlist = bomchildlist.Where(a => a.bom_id == bom.Id).ToList();
+
+            int idx = 1;
+            foreach (var c in childlist)
+            {
+                string childNum = dto.num + "." + idx.ToString();
+                long order_num = long.Parse(dto.num_order.ToString() + (idx.ToString().PadLeft(3, '0')));
+
+                var icitem = icitemlist.Where(a => a.Id == c.icitem_id).FirstOrDefault();
+                var childBom = bomlist.Where(a => a.icitem_id == c.icitem_id).FirstOrDefault();
+                //如果此明细查的到BOM信息,则代表此child是一个子BOM。
+                if (childBom != null)
+                {
+                    var cdto = new BomChildExamineDto();
+                    cdto.id = help.NextId();
+                    cdto.level = level;
+                    cdto.parent_id = dto.id;
+                    cdto.bom_child_id = c.Id;
+                    cdto.qty = c.qty.Value;
+                    cdto.backflush = c.backflush;
+                    cdto.num = childNum;
+                    cdto.num_order = order_num;
+                    cdto.isbom = 1;
+                    cdto.is_replace = c.is_replace;
+                    cdto.haveicsubs = c.haveicsubs;
+                    cdto.substitute_code = c.substitute_code;
+                    cdto.icitem_ids = c.icitem_ids;
+                    cdto.type = type;
+                    cdto.item_id = childBom.icitem_id;
+                    cdto.bom_id = childBom.Id;
+                    cdto.bom_number = childBom.bom_number;
+                    //递归寻找子级
+                    GetBomList(bomlist, bomchildlist, icitemlist, cdto, returnlist, type);
+                }
+                else
+                {
+                    if (icitem != null)
+                    {
+                        var childDto = new BomChildExamineDto();
+                        childDto.level = level;
+                        childDto.bom_id = dto.bom_id;
+                        childDto.bom_child_id = c.Id;
+                        childDto.id = help.NextId();
+                        childDto.parent_id = dto.id;
+                        childDto.item_id = icitem.Id;
+                        childDto.item_name = icitem.name;
+                        childDto.item_code = icitem.number;
+                        childDto.num = childNum;
+                        childDto.num_order = order_num;
+                        childDto.model = icitem.model;
+                        childDto.unit = c.unit;
+                        childDto.erp_cls = icitem.erp_cls;
+                        childDto.erp_cls_name = icitem.erp_cls_name;
+                        childDto.backflush = c.backflush;
+                        childDto.qty = c.qty.Value;
+                        childDto.isbom = 0;
+                        childDto.is_replace = c.is_replace;
+                        childDto.haveicsubs = c.haveicsubs;
+                        childDto.substitute_code = c.substitute_code;
+                        childDto.icitem_ids = c.icitem_ids;
+                        childDto.type = type;
+                        childDto.item_number = icitem.number;
+                        returnlist.Add(childDto);
+                    }
+                }
+                idx++;
+            }
+
+        }
+
+        /// <summary>
+        /// BOM替代关系预处理
+        /// </summary>
+        /// <param name="returnlist"></param>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="sublist"></param>
+        /// <param name="suballlist"></param>
+        /// <param name="subdtllist"></param>
+        public void BomSubstitute(List<BomChildExamineDto> returnlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, List<ic_substitute> sublist, List<ic_substitute_all> suballlist, List<ic_substitute_all_dtl> subdtllist)
+        {
+            List<long> childidList = new List<long>();
+            int type = 1;
+            List<BomChildExamineDto> addlist = new List<BomChildExamineDto>();
+
+            //除顶级外,其他层级关系全带出来。生成平铺
+            foreach (var item in returnlist)
+            {
+                //最顶级、虚拟件
+                if (item.level == 1 || item.erp_cls == 4 || childidList.Contains(item.bom_child_id.GetValueOrDefault()))
+                {
+                    continue;
+                }
+                //有替代关系
+                if (item.haveicsubs != 1)
+                {
+                    continue;
+                }
+                if (!string.IsNullOrEmpty(item.icitem_ids))
+                {
+                    long cid = 1;
+                    var cids = item.icitem_ids.Split(',');
+                    foreach (var c in cids)
+                    {
+                        if (long.TryParse(c, out cid))
+                        {
+                            childidList.Add(cid);
+                        }
+                    }
+                }
+
+
+                //找到当前物料的替代群组关系集
+                var sl = sublist.Find(s => s.substitute_code == item.substitute_code);
+                if (sl != null)
+                {
+                    var sall = suballlist.Where(s => s.substitute_id == sl.Id).ToList();
+                    foreach (var sal in sall)
+                    {
+                        var sadl = subdtllist.Where(s => s.substitute_allid == sal.Id).ToList();
+                        foreach (var dtl in sadl)
+                        {
+                            if (sal.main_material.GetValueOrDefault() != 1)
+                            {
+                                //递归将替代关系组装出来。
+                                SubstitutePretreatment(sl, sal, dtl, item, addlist, icitemlist, bomlist, bomchildlist, type);
+                            }
+                            else
+                            {
+                                //将主料赋值上属性
+                                var dtlitem = returnlist.Find(s => s.item_id == dtl.icitem_id && s.level == item.level);
+                                dtlitem.substitute_all_num = sal.order_num;//群组优先级
+                            }
+                        }
+
+
+
+                    }
+                }
+            }
+            returnlist.AddRange(addlist);
+        }
+
+        /// <summary>
+        /// 替代关系递归组装出来
+        /// </summary>
+        /// <param name="sal"></param>
+        /// <param name="dtl"></param>
+        /// <param name="toDto"></param>
+        /// <param name="returnlist"></param>
+        /// <param name="icitemlist"></param>
+        /// <param name="bomlist"></param>
+        /// <param name="bomchildlist"></param>
+        public void SubstitutePretreatment(ic_substitute sl, ic_substitute_all sal, ic_substitute_all_dtl dtl, BomChildExamineDto toDto, List<BomChildExamineDto> returnlist, List<ic_item> icitemlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, int type)
+        {
+            //如果dtl对应的icitem是BOM,还需要向下继续展开。
+
+            //List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
+            var dto = new BomChildExamineDto();
+            var bom = bomlist.Where(s => s.icitem_id == dtl.icitem_id).FirstOrDefault();
+            var icitem = icitemlist.Find(s => s.Id == dtl.icitem_id);
+            if (icitem == null)
+            {
+                return;
+            }
+            dto.id = help.NextId();
+            dto.level = toDto.level;
+            dto.parent_id = toDto.parent_id;
+            dto.item_id = icitem.Id;
+            dto.item_name = icitem.name;
+            dto.item_code = icitem.number;
+            dto.num = toDto.num;
+            dto.num_order = toDto.num_order;
+            dto.model = icitem.model;
+            dto.unit = icitem.unit;
+            dto.erp_cls = icitem.erp_cls;
+            dto.erp_cls_name = icitem.erp_cls_name;
+            dto.backflush = toDto.backflush;
+            //dto.qty = toDto.qty;
+            //dto.replace_amount = dtl.replace_amount.Value;
+            dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+            dto.is_replace = 0;
+            dto.haveicsubs = 0;
+            dto.substitute_code = "";
+            dto.icitem_ids = "";
+            dto.substitute_strategy = sl.substitute_strategy == null ? 0 : sl.substitute_strategy.Value;//替代策略
+            dto.substitute_mode = sl.substitute_mode == null ? 0 : sl.substitute_mode.Value;//替代方式
+            dto.type = type;
+            dto.substitute_all_num = sal.order_num;//群组优先级
+            if (bom != null)
+            {
+                dto.bom_id = bom.Id;
+
+                dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
+                dto.isbom = 1;
+                dto.is_replace = 0;
+                dto.haveicsubs = 0;
+                dto.substitute_code = "";
+                dto.icitem_ids = "";
+                GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
+            }
+            else
+            {
+                dto.bom_id = null;
+                dto.isbom = 0;
+                returnlist.Add(dto);
+            }
+        }
+
+    }
+}

+ 39 - 1265
MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs

@@ -210,6 +210,17 @@ namespace Business.ResourceExamineManagement
         /// </summary>
         private readonly MorderAppService _morderAppService;
 
+        
+        /// <summary>
+        /// 预处理
+        /// </summary>
+        private readonly PretreatmentAppService _pretreatmentAppService;
+
+        /// <summary>
+        /// 计算BOM平铺物料情况
+        /// </summary>
+        private readonly CalcBomViewAppService _CalcBomViewAppService;
+
         private List<ICItemLeadTimeDto> leadTimeList;
 
         private List<ic_item_pur> supplierList;
@@ -269,7 +280,9 @@ namespace Business.ResourceExamineManagement
             IRepository<ic_item_pur, long> mysql_ic_item_pur,
             IRepository<ic_plan, long> mysql_ic_plan,
             ProductExamineAppService productExamineAppService,
-            MorderAppService morderAppService
+            MorderAppService morderAppService,
+            PretreatmentAppService pretreatmentAppService,
+            CalcBomViewAppService calcbomviewAppService
             )
         {
             _ic_item = ic_item;
@@ -311,6 +324,8 @@ namespace Business.ResourceExamineManagement
             _mysql_ic_plan = mysql_ic_plan;
             _productExamineAppService = productExamineAppService;
             _morderAppService = morderAppService;
+            _pretreatmentAppService = pretreatmentAppService;
+            _CalcBomViewAppService = calcbomviewAppService;
         }
         #endregion
 
@@ -326,6 +341,7 @@ namespace Business.ResourceExamineManagement
             param.sorderId = input.sorderId;
             param.tenantId = input.tenantId;
             param.factoryId = input.factoryId;
+            
 
             //资源检查结果
             PschedDto rtn = new PschedDto();
@@ -382,11 +398,18 @@ namespace Business.ResourceExamineManagement
             itemIds.AddRange(subdtllist.Select(p => p.icitem_id).ToList());
             List<ic_item> icitemlist = _ic_item.GetManyByCondition(p => itemIds.Contains(p.Id) && !p.IsDeleted).Result;
 
+            //物料库存
+            var stocklist = _ic_item_stock.GetManyByCondition(p => p.factory_id == param.factoryId && itemIds.Contains(p.icitem_id)).Result;
+
             //物料提前期
             leadTimeList = GetLeadTime(itemIds, input.tenantId, input.factoryId);//提前期列表
             supplierList = GetSupplier(itemIds, input.tenantId, input.factoryId);//供应商列表
             planList = GetICPlan(itemIds, input.tenantId, input.factoryId);//plan列表
 
+            _CalcBomViewAppService.param = param;
+            _CalcBomViewAppService.planList = planList;
+            _CalcBomViewAppService.leadTimeList= leadTimeList;
+            _CalcBomViewAppService.supplierList = supplierList;
             foreach (var item in sentrys)
             {
                 //工单资源检查信息
@@ -398,13 +421,17 @@ namespace Business.ResourceExamineManagement
                 //获取当前物料bom数据
                 var childBom = boms.Where(p => p.item_number == item.item_number).FirstOrDefault();
                 //bom层级组装
-                var getBomList = BomPretreatment(childBom.Id, bomlist, bomchildlist, icitemlist);
+                var getBomList = _pretreatmentAppService.BomPretreatment(childBom.Id, bomlist, bomchildlist, icitemlist);
                 //bom替代关系组装
-                BomSubstitute(getBomList, bomlist, bomchildlist, icitemlist, sublist, suballlist, subdtllist);
+                _pretreatmentAppService.BomSubstitute(getBomList, bomlist, bomchildlist, icitemlist, sublist, suballlist, subdtllist);
                 //库存初始化
-                BomStock(getBomList);
+                _CalcBomViewAppService.BomStock(getBomList, stocklist);
                 //计算
-                calcTest(getBomList, bangid, item.Id, item.qty.Value, input, item.plan_date, sklist, item, icitemlist);
+                _CalcBomViewAppService.CalcView(getBomList, bangid, item.qty.Value, input, item.plan_date, sklist, item, icitemlist);
+
+                //批量保存 后期考虑子工单
+                await _mes_morder.InsertMany(_CalcBomViewAppService.mordersList);
+                await _mes_moentry.InsertMany(_CalcBomViewAppService.moentriesList);
 
                 //TODO:最晚开始时间
                 var curFacDtl = leadTimeList.FirstOrDefault(p => p.item_id == childBom.icitem_id);
@@ -419,9 +446,14 @@ namespace Business.ResourceExamineManagement
                 //生成工单 TODO:0=产品数量
                 //GenerateMorder(o, 0);
             }
+            if (_CalcBomViewAppService.mooccupyAllList.Any())
+            {
+                await _mes_mooccupy.InsertMany(_CalcBomViewAppService.mooccupyAllList);
+            }
+
             //订单行资源检查明细list
-            rtn.srm_pr_list = SRMPRDtoList;
-            rtn.order_list = orderList;
+            rtn.srm_pr_list = _CalcBomViewAppService.SRMPRDtoList;
+            rtn.order_list = _CalcBomViewAppService.orderList;
             rtn.examines = examines;
             rtn.sklist = sklist;
 
@@ -558,1264 +590,6 @@ namespace Business.ResourceExamineManagement
             }
         }
 
-        /// <summary>
-        /// 清处数据库快照
-        /// </summary>
-        /// <returns></returns>
-        public async Task ClearSnapShot(long bangid)
-        {
-            //清除物料库存数据
-            await _ic_item_stock.Delete(p=>p.bang_id == bangid);
-
-            //清除工单占用记录表
-            await _mes_mooccupy.Delete(p => p.bang_id == bangid);
-
-            //清除工单主表
-            await _mes_morder.Delete(p => p.bang_id == bangid);
-
-            //清除工单子表
-            await _mes_moentry.Delete(p => p.bang_id == bangid);
-
-            //清除采购订单
-            await _srm_po_main.Delete(p => p.bang_id == bangid);
-
-            //清除采购订单明细
-            await _srm_po_list.Delete(p => p.bang_id == bangid);
-
-            //清除采购订单占用详情
-            await _srm_po_occupy.Delete(p => p.bang_id == bangid);
-
-            //清除工厂物料明细表
-            await _ic_factory_details.Delete(p => p.bang_id == bangid);
-
-            //清除物料采购计划表
-            await _ic_plan.Delete(p => p.bang_id == bangid);
-
-            //清除物料采购报价单
-            await _ic_item_pur.Delete(p => p.bang_id == bangid);
-        }
-
-        /// <summary>
-        /// BOM预处理
-        /// </summary>
-        /// <param name="orderid"></param>
-        /// <param name="BomId"></param>
-        /// <param name="Quantity"></param>
-        public List<BomChildExamineDto> BomPretreatment(long? BomId, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist)
-        {
-            if (BomId == null)
-            {
-                //throw new bu
-            }
-            List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
-
-            var bom = bomlist.Find(s => s.Id == BomId);
-            if (bom == null)
-            {
-                return returnlist;
-            }
-
-            var dto = new BomChildExamineDto();
-            dto.item_id = bom.icitem_id;
-            dto.bom_id = BomId.Value;
-            dto.bom_number = bom.bom_number;
-            dto.level = 1;
-            dto.id = help.NextId();
-            dto.parent_id = help.NextId();
-            dto.qty = 1;
-            dto.num = "1";
-            dto.isbom = 1;
-            dto.is_replace = 0;
-            dto.haveicsubs = 0;
-            dto.substitute_code = "";
-            dto.icitem_ids = "";
-            int type = 0;
-            GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
-            return returnlist;
-        }
-
-        /// <summary>
-        /// BOM预处理层级组装
-        /// </summary>
-        /// <param name="bomlist"></param>
-        /// <param name="bomchildlist"></param>
-        /// <param name="icitemlist"></param>
-        /// <param name="dto"></param>
-        /// <param name="returnlist"></param>
-        public void GetBomList(List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, BomChildExamineDto dto, List<BomChildExamineDto> returnlist, int type)
-        {
-            int level = dto.level + 1;//初始化定义level层级
-
-            var bom = bomlist.Where(s => s.Id == dto.bom_id).FirstOrDefault();
-            ic_item item = new ic_item();
-            if (bom != null)
-            {
-                item = icitemlist.Where(a => a.Id == bom.icitem_id).FirstOrDefault();
-            }
-            else
-            {
-                item = icitemlist.Where(a => a.Id == dto.item_id).FirstOrDefault();
-            }
-            if (item == null)
-            {
-                return;
-            }
-            dto.item_id = item.Id;
-            dto.item_name = bom.item_name;
-            dto.item_code = bom.item_number;
-            dto.model = item.model;
-            dto.unit = bom.unit;
-            dto.erp_cls = item.erp_cls;
-            dto.erp_cls_name = item.erp_cls_name;
-            dto.type = type;
-            dto.item_number = item.number;
-
-            //var bdto = ObjectMapper.Map<ic_bom,BomChildExamineDto>(bom);
-            returnlist.Add(dto);
-            var childlist = bomchildlist.Where(a => a.bom_id == bom.Id).ToList();
-
-            int idx = 1;
-            foreach (var c in childlist)
-            {
-                string childNum = dto.num + "." + idx.ToString();
-                var icitem = icitemlist.Where(a => a.Id == c.icitem_id).FirstOrDefault();
-                var childBom = bomlist.Where(a => a.icitem_id == c.icitem_id).FirstOrDefault();
-                //如果此明细查的到BOM信息,则代表此child是一个子BOM。
-                if (childBom != null)
-                {
-                    var cdto = new BomChildExamineDto();
-                    cdto.id = help.NextId();
-                    cdto.level = level;
-                    cdto.parent_id = dto.id;
-                    cdto.bom_child_id = c.Id;
-                    cdto.qty = c.qty.Value;
-                    cdto.backflush = c.backflush;
-                    cdto.num = childNum;
-                    cdto.isbom = 1;
-                    cdto.is_replace = c.is_replace;
-                    cdto.haveicsubs = c.haveicsubs;
-                    cdto.substitute_code = c.substitute_code;
-                    cdto.icitem_ids = c.icitem_ids;
-                    cdto.type = type;
-                    cdto.item_id = childBom.icitem_id;
-                    cdto.bom_id = childBom.Id;
-                    cdto.bom_number = childBom.bom_number;
-                    //递归寻找子级
-                    GetBomList(bomlist, bomchildlist, icitemlist, cdto, returnlist, type);
-                }
-                else
-                {
-                    if (icitem != null)
-                    {
-                        var childDto = new BomChildExamineDto();
-                        childDto.level = level;
-                        childDto.bom_id = dto.bom_id;
-                        childDto.bom_child_id = c.Id;
-                        childDto.id = help.NextId();
-                        childDto.parent_id = dto.id;
-                        childDto.item_id = icitem.Id;
-                        childDto.item_name = icitem.name;
-                        childDto.item_code = icitem.number;
-                        childDto.num = childNum;
-                        childDto.model = icitem.model;
-                        childDto.unit = c.unit;
-                        childDto.erp_cls = icitem.erp_cls;
-                        childDto.erp_cls_name = icitem.erp_cls_name;
-                        childDto.backflush = c.backflush;
-                        childDto.qty = c.qty.Value;
-                        childDto.isbom = 0;
-                        childDto.is_replace = c.is_replace;
-                        childDto.haveicsubs = c.haveicsubs;
-                        childDto.substitute_code = c.substitute_code;
-                        childDto.icitem_ids = c.icitem_ids;
-                        childDto.type = type;
-                        childDto.item_number = icitem.number;
-                        returnlist.Add(childDto);
-                    }
-                }
-                idx++;
-            }
-
-        }
-
-
-        /// <summary>
-        /// BOM替代关系预处理
-        /// </summary>
-        public void BomSubstitute(List<BomChildExamineDto> returnlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, List<ic_item> icitemlist, List<ic_substitute> sublist, List<ic_substitute_all> suballlist, List<ic_substitute_all_dtl> subdtllist)
-        {
-            List<long> childidList = new List<long>();
-            int type = 1;
-            List<BomChildExamineDto> addlist = new List<BomChildExamineDto>();
-
-            //除顶级外,其他层级关系全带出来。生成平铺
-            foreach (var item in returnlist)
-            {
-                //最顶级、虚拟件
-                if (item.level == 1 || item.erp_cls == 4 || childidList.Contains(item.bom_child_id.GetValueOrDefault()))
-                {
-                    continue;
-                }
-                //有替代关系
-                if (item.haveicsubs != 1)
-                {
-                    continue;
-                }
-                if (!string.IsNullOrEmpty(item.icitem_ids))
-                {
-                    long cid = 1;
-                    var cids = item.icitem_ids.Split(',');
-                    foreach (var c in cids)
-                    {
-                        if (long.TryParse(c, out cid))
-                        {
-                            childidList.Add(cid);
-                        }
-                    }
-                }
-
-
-                //找到当前物料的替代群组关系集
-                var sl = sublist.Find(s => s.substitute_code == item.substitute_code);
-                if (sl != null)
-                {
-                    var sall = suballlist.Where(s => s.substitute_id == sl.Id).ToList();
-                    foreach (var sal in sall)
-                    {
-                        var sadl = subdtllist.Where(s => s.substitute_allid == sal.Id).ToList();
-                        List<long> dtlItemId = sadl.Select(m => m.icitem_id).ToList();
-                        var dtlitemlist = _ic_item.GetManyByCondition(p => dtlItemId.Contains(p.Id) && !p.IsDeleted).Result;
-                        icitemlist.AddRange(dtlitemlist);
-                        foreach (var dtl in sadl)
-                        {
-                            if (sal.main_material.GetValueOrDefault() != 1)
-                            {
-                                //递归将替代关系组装出来。
-                                SubstitutePretreatment(sl, sal, dtl, item, addlist, icitemlist, bomlist, bomchildlist, type);
-                            }
-                            else
-                            {
-                                //将主料赋值上属性
-                                var dtlitem = returnlist.Find(s => s.item_id == dtl.icitem_id && s.level == item.level);
-                                dtlitem.substitute_all_num = sal.order_num;//群组优先级
-                            }
-                        }
-
-
-
-                    }
-                }
-            }
-            returnlist.AddRange(addlist);
-        }
-
-        /// <summary>
-        /// 替代关系递归组装出来
-        /// </summary>
-        /// <param name="sal"></param>
-        /// <param name="dtl"></param>
-        /// <param name="toDto"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="icitemlist"></param>
-        /// <param name="bomlist"></param>
-        /// <param name="bomchildlist"></param>
-        public void SubstitutePretreatment(ic_substitute sl, ic_substitute_all sal, ic_substitute_all_dtl dtl, BomChildExamineDto toDto, List<BomChildExamineDto> returnlist, List<ic_item> icitemlist, List<ic_bom> bomlist, List<ic_bom_child> bomchildlist, int type)
-        {
-            //如果dtl对应的icitem是BOM,还需要向下继续展开。
-
-            //List<BomChildExamineDto> returnlist = new List<BomChildExamineDto>();
-            var dto = new BomChildExamineDto();
-            var bom = bomlist.Where(s => s.icitem_id == dtl.icitem_id).FirstOrDefault();
-            var icitem = icitemlist.Find(s => s.Id == dtl.icitem_id);
-            if (icitem == null)
-            {
-                return;
-            }
-            dto.id = help.NextId();
-            dto.level = toDto.level;
-            dto.parent_id = toDto.parent_id;
-            dto.item_id = icitem.Id;
-            dto.item_name = icitem.name;
-            dto.item_code = icitem.number;
-            dto.num = toDto.num;
-            dto.model = icitem.model;
-            dto.unit = icitem.unit;
-            dto.erp_cls = icitem.erp_cls;
-            dto.erp_cls_name = icitem.erp_cls_name;
-            dto.backflush = toDto.backflush;
-            //dto.qty = toDto.qty;
-            //dto.replace_amount = dtl.replace_amount.Value;
-            dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
-            dto.is_replace = 0;
-            dto.haveicsubs = 0;
-            dto.substitute_code = "";
-            dto.icitem_ids = "";
-            dto.substitute_strategy = sl.substitute_strategy == null ? 0 : sl.substitute_strategy.Value;//替代策略
-            dto.substitute_mode = sl.substitute_mode == null ? 0 : sl.substitute_mode.Value;//替代方式
-            dto.type = type;
-            dto.substitute_all_num = sal.order_num;//群组优先级
-            if (bom != null)
-            {
-                dto.bom_id = bom.Id;
-
-                dto.qty = dtl.replace_amount == null ? 1 : dtl.replace_amount.Value;
-                dto.isbom = 1;
-                dto.is_replace = 0;
-                dto.haveicsubs = 0;
-                dto.substitute_code = "";
-                dto.icitem_ids = "";
-                GetBomList(bomlist, bomchildlist, icitemlist, dto, returnlist, type);
-            }
-            else
-            {
-                dto.bom_id = null;
-                dto.isbom = 0;
-                returnlist.Add(dto);
-            }
-        }
-
-        /// <summary>
-        /// 计算物料库存量
-        /// </summary>
-        /// <param name="returnlist"></param>
-        public void BomStock(List<BomChildExamineDto> returnlist)
-        {
-            returnlist = returnlist.OrderBy(s => s.num).ToList();
-            //获取当前工厂下物料库存数据
-            List<long> icitemIds = returnlist.Select(c => c.item_id).ToList();
-            var stocklist = _ic_item_stock.GetManyByCondition(p => p.factory_id == param.factoryId && icitemIds.Contains(p.icitem_id)).Result;
-            //计算剩余库存
-            foreach (var item in returnlist)
-            {
-                if (item.erp_cls == 4)//虚拟件不计算
-                {
-                    continue;
-                }
-                //非虚拟件
-                //当前物料的库存数量
-                decimal stockQty = stocklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.sqty.GetValueOrDefault());
-                //获取当前订单其他订单行当前物料的占用数量
-                //decimal otherStockQty = occupylist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
-                //当前订单行物料库存情况
-                //item.sqty = stockQty - otherStockQty;
-                item.sqty = stockQty;
-            }
-        }
-
-        /// <summary>
-        /// 替代关系计算
-        /// </summary>
-        /// <param name="returnlist"></param>
-        /// <param name="bangid"></param>
-        /// <param name="orderid"></param>
-        /// <param name="count"></param>
-        /// <param name="input"></param>
-        /// <param name="plan_date"></param>
-        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid, decimal count, SeorderentryDto input, DateTime
-            ? plan_date, List<ic_item_stockoccupy> sklist, crm_seorderentry sentrys,List<ic_item> icitemlist)
-        {
-            //第一级
-            returnlist = returnlist.OrderBy(s => s.num).ToList();
-            var childList = returnlist.Where(s => s.parent_id == returnlist[0].id && s.type == 0).OrderBy(s => s.num).ToList();
-
-            var planList = GetICPlan(returnlist.Select(p => p.item_id).ToList(), bangid, param.factoryId);//plan列表
-
-            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
-            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
-            List<long> calcIds = new List<long>();
-            //先处理下最顶级的产品需要数量
-            returnlist[0].needCount = returnlist[0].qty * count;
-            returnlist[0].lack_qty = returnlist[0].needCount - returnlist[0].sqty;
-
-            foreach (var item in returnlist)
-            {
-                if (item.level == 1)
-                {
-                    continue;
-                }
-                //循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
-                CaclMaterialShortage(returnlist, item, count);
-            }
-            Mes_MorderDto mes_MorderDto = new Mes_MorderDto();
-            if (returnlist[0].lack_qty > 0)
-            {
-                //获取物料详情
-                var ic_item = icitemlist.Find(s => s.Id == returnlist[0].item_id);
-                var mooccupylist = _morderAppService.CheckMorder(returnlist[0].bom_number, returnlist[0].lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
-                decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
-                returnlist[0].mo_qty = moo_qty;
-                if (moo_qty == returnlist[0].lack_qty)
-                {
-                    //在制完全足够
-                    returnlist[0].lack_qty = 0;
-                    returnlist[0].satisfy_time = mooccupylist[0].moo_etime;
-                    returnlist[0].stock_state = 1;
-                    return;
-                }
-                else
-                {
-                    //占用不够,占用后减少缺料数量
-                    returnlist[0].lack_qty -= moo_qty;
-                    //先设定在制的齐套时间
-                    returnlist[0].satisfy_time = mooccupylist[0]?.moo_etime;
-                    returnlist[0].stock_state = 0;
-                    //生成主工单
-                    GenerateMorderDto generateMorderDto = new GenerateMorderDto()
-                    {
-                        seorderentry = sentrys,
-                        ic_Item = ic_item,
-                        BomNumber = returnlist[0].bom_number,
-                        version = returnlist[0].version,
-                        number = returnlist[0].item_number,
-                        Quantity = returnlist[0].lack_qty,
-                        morder_type = "销售工单",
-                        work_order_type = "常规工单",
-                        morder_state = "初始",
-
-                    };
-                    //生成主工单
-                    mes_MorderDto = _morderAppService.GenerateMorder(generateMorderDto);
-                }
-            }
-            else {
-                returnlist[0].satisfy_time = DateTime.Now;
-                returnlist[0].stock_state = 1;
-                return;
-            }
-
-            //这是从上往下展开计算缺料和可制
-            calcTest2(returnlist[0], childList, returnlist, sklist);
-            //returnlist[0].kz = childList.Min(s => s.kz);//得到最小可制数量。
-            //再加个循环,来根据替代关系里的检查结果,根据规则明确使用和生成占用关系。
-            CalcIcitem(childList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
-            returnlist[0].kitting_time = childList.Max(s => s.kitting_time);
-            //这里更新产品得满足时间。
-            if (mes_MorderDto != null)
-            {
-                //主工单最后计算满足日期
-                var mes_Morders = mes_MorderDto.mes_Morders.Where(x => x.parent_id == null).FirstOrDefault();
-                if (mes_Morders != null)
-                {
-                    if (!string.IsNullOrEmpty(mes_Morders.bom_number))
-                    {
-                        //var ProductiveDate = ProductiveExamine(mes_Morders.bom_number, returnlist[0].version, (int)mes_Morders.morder_production_number.Value);
-                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
-                        {
-                            bom_number = mes_Morders.bom_number,
-                            version = returnlist[0].version,
-                            packages = (int)mes_Morders.morder_production_number.Value,
-                            tenantId = param.tenantId,
-                            factoryId = param.factoryId
-
-                        };
-                        var plan = planList.Find(x => x.icitem_id == returnlist[0].item_id);
-                        var ProductiveDate = _productExamineAppService.ProductiveExamine(prodExamine);
-                        var Day = ProductiveDate.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
-                        mes_Morders.moentry_sys_stime = returnlist[0].kitting_time.Value.AddDays(1);//数据齐套完成后隔天开始生产;
-                        //结束日期=开始时间+生产时长+自检提前期+入库提前期+发运提前期;
-                        var LeadTime = Day + plan.self_inspection_date.Value + plan.Shipping_date.Value + plan.Warehousing_date.Value;
-                        mes_Morders.moentry_sys_etime = mes_Morders.moentry_sys_stime.Value.AddDays((double)Day);
-                        mes_Morders.morder_need_time = ProductiveDate.Result;
-                        //满足资源检查的时间需加上提前期
-                        returnlist[0].satisfy_time = mes_Morders.moentry_sys_stime.Value.AddDays((double)LeadTime);
-                    }
-                    //批量保存 后期考虑子工单
-                    _mes_morder.InsertMany(mes_MorderDto.mes_Morders);
-                    _mes_moentry.InsertMany(mes_MorderDto.mes_Moentries);
-                }
-            }
-        }
-
-        /// <summary>
-        /// 循环计算物料情况
-        /// </summary>
-        /// <param name="childList"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="bangid"></param>
-        /// <param name="orderid"></param>
-        /// <param name="input"></param>
-        /// <param name="sklist"></param>
-        /// <param name="plan_date"></param>
-        public void CalcIcitem(List<BomChildExamineDto> childList, List<BomChildExamineDto> returnlist, long bangid, SeorderentryDto input, List<ic_item_stockoccupy> sklist, DateTime
-            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
-        {
-            foreach (var item in childList)
-            {
-                var parent = returnlist.Find(s => s.id == item.parent_id);
-                if (parent.stock_state == 0)
-                {
-                    if (item.haveicsubs == 1)
-                    {
-                        //如果有替代关系,根据群组来明确使用哪个群组的替代料。按整批和混用逻辑来算
-                        // 如果有群组替代,就移除掉被检查过的记录 item.icitem_ids
-                        CalcStrategy(item, returnlist, bangid, sklist, input, plan_date, icitemlist, sentrys);
-                    }
-                    else
-                    {
-                        Calczykc(item, parent, sklist);
-
-                        //直接占用库存,缺料就生成采购
-                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
-                        itemStockoccupyDto.bang_id = bangid;
-                        itemStockoccupyDto.icitem_id = item.item_id;
-                        itemStockoccupyDto.item_no = item.num;
-                        item.kitting_time = DateTime.Now;
-                        item.is_use = true;
-                        StartProcessing(item,icitemlist,returnlist,plan_date,sentrys,sklist,itemStockoccupyDto,bangid,input);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// 针对缺料开始进行处理
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="icitemlist"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="plan_date"></param>
-        /// <param name="sentrys"></param>
-        /// <param name="sklist"></param>
-        /// <param name="itemStockoccupyDto"></param>
-        /// <param name="bangid"></param>
-        /// <param name="input"></param>
-        public void StartProcessing(BomChildExamineDto item, List<ic_item> icitemlist, List<BomChildExamineDto> returnlist, DateTime
-            ? plan_date, crm_seorderentry sentrys, List<ic_item_stockoccupy> sklist, ic_item_stockoccupy itemStockoccupyDto, long bangid, SeorderentryDto input)
-        {
-            var parent = returnlist.Find(s => s.id == item.parent_id);
-            if (item.lack_qty > 0)
-            {
-                var cilList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).OrderBy(k => k.num).ToList();
-                //如果缺料,占用库存,然后走采购或自制
-                if (item.sqty > 0)
-                {
-                    itemStockoccupyDto.quantity = item.sqty;
-                    sklist.Add(itemStockoccupyDto);
-                }
-                item.use_qty = item.sqty;
-                if (item.erp_cls == 1)
-                {
-                    var ic_item = icitemlist.Find(s => s.Id == item.item_id);
-                    var mooccupylist = _morderAppService.CheckMorder(item.bom_number, item.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
-                    decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
-                    item.mo_qty = moo_qty;
-                    if (moo_qty == returnlist[0].lack_qty)
-                    {
-                        //在制完全足够
-                        item.lack_qty = 0;
-                        item.kitting_time = mooccupylist[0].moo_etime;
-                        item.stock_state = 1;
-                    }
-                    else
-                    {
-                        item.lack_qty -= moo_qty;
-                        item.kitting_time=DateTime.Now;
-                        //先计算末级数据的齐套时间。
-                        if (cilList.Count() > 0)
-                        {
-                            CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
-                            item.kitting_time = cilList.Max(s => s.kitting_time);
-                        }
-
-                        //走自制
-                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
-                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
-                        {
-                            bom_number = item.bom_number,
-                            version = item.version,
-                            packages = (int)item.lack_qty,
-                            tenantId = param.tenantId,
-                            factoryId = param.factoryId
-
-                        };
-                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
-                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
-                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
-                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
-                        var ktime = item.kitting_time.Value.AddDays((double)Day);
-                        item.kitting_time = ktime > mooccupylist[0].moo_etime ? ktime : mooccupylist[0].moo_etime;
-                    }
-                }
-                else if (item.erp_cls == 3)
-                {
-                    //采购申请
-                    var SRMPRDto = CreateSRMPR(item, input.tenantId, input.factoryId, bangid, item.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
-                    item.kitting_time = SRMPRDto.lastStartTmie;
-                    SRMPRDtoList.Add(SRMPRDto);
-                }
-                else if (item.erp_cls == 2)
-                {
-                    //先计算末级数据的齐套时间。
-                    if (cilList.Count() > 0)
-                    {
-                        CalcIcitem(cilList, returnlist, bangid, input, sklist, plan_date, icitemlist, sentrys);
-                        item.kitting_time = cilList.Max(s => s.kitting_time);
-                    }
-                    //1.先生成委外工单。
-                    var mesorder = CreateMesOOder(item, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
-                    item.kitting_time = mesorder.ooentry_etime;
-                    orderList.Add(mesorder);
-                }
-            }
-            else
-            {
-                //如果父级缺料,则本级等于父级缺料*本级使用数量
-                if (parent != null)
-                {
-                    item.use_qty = parent.lack_qty * item.qty;
-                    itemStockoccupyDto.quantity = item.use_qty;
-                }
-                sklist.Add(itemStockoccupyDto);
-            }
-        }
-
-
-        /// <summary>
-        /// 平铺计算物料情况
-        /// </summary>
-        /// <param name="returnlist"></param>
-        /// <param name="item"></param>
-        /// <param name="count"></param>
-        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item, decimal count)
-        {
-            var parent = returnlist.Find(s => s.id == item.parent_id);
-            //当前物料总共需要数量
-            item.needCount = parent.needCount * item.qty;
-            /*//当前库存可以满足的数量
-            item.satisfyNum = item.sqty;
-            //总需要数量减去库存量,得出缺料数量
-            item.lack_qty = item.needCount - item.satisfyNum;
-            //如果不满足,计算子物料,或者计算替代料
-            if (item.lack_qty < 0)
-            {
-                //库存满足
-                item.stock_state = 1;
-                item.lack_qty = 0;
-            }
-            else
-            {
-                item.stock_state = 0;
-            }*/
-        }
-
-        /// <summary>
-        /// 根据占用情况重新计算占用
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="sklist"></param>
-        public void RecalculationStock(BomChildExamineDto item, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist)
-        {
-            //再计算一边占用情况,这里根据父级产品额缺料量*当前子料的使用数量-子料库存量。得出当前子物料的缺料数量
-            var parent = returnlist.Find(s => s.id == item.parent_id);
-            decimal stockQty = sklist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
-            item.sqty = item.sqty - stockQty;
-            item.lack_qty = parent.lack_qty * item.qty - item.sqty;
-            item.lack_qty = item.lack_qty > 0 ? item.lack_qty : 0;
-            item.stock_state = item.lack_qty > 0 ? 0 : 1;
-        }
-
-        /// <summary>
-        /// 根据替代策略计算
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="bangid"></param>
-        /// <param name="sklist"></param>
-        /// <param name="input"></param>
-        /// <param name="plan_date"></param>
-        public void CalcStrategy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, List<ic_item_stockoccupy> sklist, SeorderentryDto input, DateTime
-            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
-        {
-            //提取群组关系
-            var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
-            List<BomChildExamineDto> select = new List<BomChildExamineDto>();
-            var parent = returnlist.Find(s => s.id == item.parent_id);
-            switch (item.substitute_strategy)
-            {
-                case 0://整批
-                    WholeBatchCheck(sublist, returnlist, sklist, select);
-                    //如果都需要采购的情况下,则默认使用优先级最高的
-                    WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
-                    break;
-                case 1://混用
-                    MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
-                    break;
-                case 2://整批加混用
-                    WholeBatchCheck(sublist, returnlist, sklist, select);
-                    if (select.Count() == 0)
-                    {
-                        //走混用
-                        MixedUse(item, sublist, returnlist, sklist, bangid, parent, input, plan_date, icitemlist, sentrys);
-                    }
-                    else
-                    {
-                        //走整批
-                        WholeBatch(item, sublist, returnlist, sklist, select, bangid, parent, input, plan_date, icitemlist, sentrys);
-                    }
-                    break;
-            }
-        }
-        /// <summary>
-        /// 整批计算
-        /// </summary>
-        /// <param name="sublist"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="sklist"></param>
-        /// <param name="select"></param>
-        public void WholeBatchCheck(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select)
-        {
-            for (int idx = 0; idx < 99; idx++)
-            {
-                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
-                if (list.Any())
-                {
-                    foreach (var s in list)
-                    {
-                        RecalculationStock(s, returnlist, sklist);
-                    }
-                    //可制计算:需要对list进行可制计算,按主料来算辅料
-                    if (list.Where(s => s.stock_state != 1).Count() == 0)
-                    {
-                        //只满足充足或可制
-                        //无缺料情况
-                        select = list;
-                        select.ForEach(s => { s.is_use = true; });
-                        break;
-                    }
-                    idx++;
-                }
-                else
-                {
-                    idx = 99;
-                }
-            }
-        }
-        /// <summary>
-        /// 整批占用
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="sublist"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="sklist"></param>
-        /// <param name="select"></param>
-        /// <param name="bangid"></param>
-        /// <param name="parent"></param>
-        /// <param name="input"></param>
-        /// <param name="plan_date"></param>
-        public void WholeBatch(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
-            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
-        {
-            if (select.Count() == 0)
-            {
-                //如果为空,则默认使用优先级为0的集合作为替代关系
-                if (item.substitute_mode == 0)
-                {
-                    //替代
-                    select = sublist.Where(s => s.type == 0).ToList();
-                }
-                else
-                {
-                    //取代
-                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
-                }
-                select.ForEach(s => { s.is_use = true; });
-            }
-            //占用库存
-            foreach (var slt in select)
-            {
-                ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
-                itemStockoccupyDto.bang_id = bangid;
-                itemStockoccupyDto.icitem_id = slt.item_id;
-                itemStockoccupyDto.item_no = slt.num;
-                slt.is_use = true;
-                StartProcessing(slt, icitemlist, returnlist, plan_date, sentrys, sklist, itemStockoccupyDto, bangid, input);
-            }
-
-        }
-
-        /// <summary>
-        /// 混用占用
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="sublist"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="sklist"></param>
-        /// <param name="bangid"></param>
-        /// <param name="parent"></param>
-        /// <param name="input"></param>
-        /// <param name="plan_date"></param>
-        public void MixedUse(BomChildExamineDto item, List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, long bangid, BomChildExamineDto parent, SeorderentryDto input, DateTime
-            ? plan_date, List<ic_item> icitemlist, crm_seorderentry sentrys)
-        {
-
-            decimal parent_lack = 0;
-            if (parent != null)
-            {
-                parent_lack = parent.lack_qty;
-            }
-            for (int idx = 0; idx < 99; idx++)
-            {
-                if (parent_lack <= 0)
-                {
-                    break;
-                }
-
-                var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
-                if (list.Any())
-                {
-                    foreach (var s in list)
-                    {
-                        RecalculationStock(s, returnlist, sklist);
-                    }
-                    decimal minMake = 99999999;
-                    foreach (var hy in list)
-                    {
-                        //混用先使用掉当前要用的数量
-                        //得到库存最小数量,去占用,然后剩余的丢第二个循环里去占用。
-                        //获取物料详情
-                        var ic_item = icitemlist.Find(s => s.Id == hy.item_id);
-                        var mooccupylist = _morderAppService.CheckMorder(hy.bom_number, hy.lack_qty, plan_date.GetValueOrDefault(), sentrys, ic_item, false).Result;
-                        decimal moo_qty = mooccupylist.Sum(s => s.moo_qty.GetValueOrDefault());
-                        decimal make = (hy.sqty + moo_qty) / hy.qty;
-                        if (Math.Floor(hy.qty) == hy.qty)
-                        {
-                            //如果物料的使用数量是小数,则按小数计算。
-                            make = Math.Floor(make);
-                        }
-                        if (minMake > make)
-                        {
-                            minMake = make;
-                        }
-                    }
-                    decimal use_p_num = 0;
-                    if (parent_lack > minMake) //20>10
-                    {
-                        use_p_num = minMake;
-                        parent_lack -= use_p_num;
-                    }
-                    else
-                    {
-                        use_p_num = parent_lack;
-                        parent_lack = 0;
-                    }
-                    //根据混用逻辑,去占用物料
-                    foreach (var zy in list)
-                    {
-                        zy.is_use = true;
-                        zy.kitting_time = DateTime.Now;
-                        if (parent_lack <= 0)
-                        {
-                            zy.stock_state = 1;
-                        }
-                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
-                        itemStockoccupyDto.bang_id = bangid;
-                        itemStockoccupyDto.icitem_id = zy.item_id;
-                        decimal moo_qty = use_p_num * zy.qty - zy.sqty;
-                        if (moo_qty > 0)
-                        {
-                            var ic_item = icitemlist.Find(s => s.Id == zy.item_id);
-                            var mooccupylist = _morderAppService.CheckMorder(zy.bom_number, moo_qty, plan_date.GetValueOrDefault(), sentrys, ic_item).Result;
-                            itemStockoccupyDto.quantity = zy.sqty;
-                            zy.use_qty = zy.sqty;
-                            zy.mo_qty = moo_qty;
-                        }
-                        else {
-                            zy.use_qty = use_p_num * zy.qty;
-                            itemStockoccupyDto.quantity = zy.use_qty;
-                        }
-                        itemStockoccupyDto.item_no = zy.num;
-                        sklist.Add(itemStockoccupyDto);
-                    }
-                    idx++;
-                }
-            }
-            if (parent_lack > 0)
-            {
-                var select = new List<BomChildExamineDto>();
-                if (item.substitute_mode == 0)
-                {
-                    //替代
-                    select = sublist.Where(s => s.type == 0).ToList();
-                }
-                else
-                {
-                    //取代
-                    select = sublist.Where(s => s.substitute_all_num == 0).ToList();
-                }
-                //对select执行采购
-                foreach (var sct in select)
-                {
-                    //找到当前物料的占用记录
-                    var itemSockoccupy = sklist.Where(s => s.icitem_id == sct.item_id).ToList();
-                    var num = parent_lack * sct.qty - itemSockoccupy.Sum(m => m.quantity);
-                    if (sct.erp_cls == 1)
-                    {
-                        //走自制
-                        //var minute = ProductiveExamine(item.bom_number, "1.0", item.lack_qty.GetInt());
-                        ProdExamineParamDto prodExamine = new ProdExamineParamDto()
-                        {
-                            bom_number = sct.bom_number,
-                            version = sct.version,
-                            packages = (int)sct.lack_qty,
-                            tenantId = param.tenantId,
-                            factoryId = param.factoryId
-
-                        };
-                        var minute = _productExamineAppService.ProductiveExamine(prodExamine);
-                        //var ProductiveDate = ProductiveExamine(BomNumber, (int)(Quantity.Value));
-                        //系统建议完工日期为 开工日期+产能检查时间=完工日期
-                        var Day = minute.Result / (60 * 10); //返回的分钟除以十个小时得出工作天数;
-                        sct.kitting_time = sct.kitting_time.Value.AddDays((double)Day);
-                    }
-                    else if (sct.erp_cls == 3)
-                    {
-                        //采购申请
-                        var SRMPRDto = CreateSRMPR(sct, input.tenantId, input.factoryId, bangid, sct.erp_cls, leadTimeList, supplierList, planList, plan_date.Value);
-                        sct.kitting_time = SRMPRDto.lastStartTmie;
-                        SRMPRDtoList.Add(SRMPRDto);
-                    }
-                    else if (sct.erp_cls == 2)
-                    {
-                        //1.先生成委外工单。
-                        var mesorder = CreateMesOOder(sct, input.tenantId, input.factoryId, bangid, leadTimeList, supplierList, plan_date.Value);
-                        sct.kitting_time = mesorder.ooentry_etime;
-                        orderList.Add(mesorder);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// 可制占用计算---暂时未用
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="bangid"></param>
-        /// <param name="kznun"></param>
-        public void Sockoccupy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, decimal kznun)
-        {
-            ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
-            itemStockoccupyDto.bang_id = bangid;
-            if (item.stock_state == 1)
-            {
-                //成品库存占用
-                //slt.needCount
-                //可制物料占用
-                //slt.kz;如果是BOM,就展开BOM占用子物料
-                itemStockoccupyDto.icitem_id = item.item_id;
-                itemStockoccupyDto.quantity = item.needCount;
-            }
-            else if (item.stock_state == 2 || item.stock_state == 3)
-            {
-                itemStockoccupyDto.quantity = item.sqty;
-                var num = item.lack_qty;//可制满足的情况下,直接占用可制。
-                var sltChild = returnlist.Where(s => s.parent_id == item.id).ToList();
-                if (sltChild.Count() > 0)
-                {
-                    //有子集,则代表每条明细的库存加可制,才是父级的可制。
-                    foreach (var c in sltChild)
-                    {
-                        Sockoccupy(c, returnlist, bangid, num);
-                    }
-                }
-            }
-            //如果存在外购或者委外
-            else if (item.stock_state == 4 || item.stock_state == 5)
-            {
-                //根据最小颗粒度
-            }
-        }
-
-        /// <summary>
-        /// 计算物料是否缺料
-        /// </summary>
-        /// <param name="parent"></param>
-        /// <param name="bzlist"></param>
-        /// <param name="returnlist"></param>
-        /// <param name="sockoccupyList"></param>
-        public void calcTest2(BomChildExamineDto parent, List<BomChildExamineDto> bzlist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
-        {
-            //从第二级开始循环
-            foreach (var item in bzlist)
-            {
-                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == 0).ToList();
-
-                //根据占用情况计算库存
-                Calczykc(item, parent, sockoccupyList);
-                //如果有子集,则丢入循环,判断下库存可制等信息。
-                calcTest2(item, childList, returnlist, sockoccupyList);
-            }
-        }
-
-        /// <summary>
-        /// 递归计算物料信息--暂未使用
-        /// </summary>
-        /// <param name="sublist"></param>
-        public void MaterialCalc(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
-        {
-            int maxIdx = sublist.Max(s => s.substitute_all_num);
-            for (int i = 0; i <= maxIdx; i++)
-            {
-                var group = sublist.Where(s => s.substitute_all_num == i).ToList();
-                // int boolCount = 0;//代表某一颗物料无需采购,可以自制,则集合+1。
-
-                //如果替代料库存不够,但是可制够,则也考虑使用优先级最高
-                foreach (var g in group)
-                {
-                    var parent = returnlist.Find(s => s.id == g.parent_id);
-                    //根据占用情况计算库存
-                    Calczykc(g, parent, sockoccupyList);
-                    /*if (g.stock_state != 1)
-                    {
-                        //判断此料是否BOM,如果是BOM,就考虑自制是否足够,此处递归检查子集
-                        var gChildList = returnlist.Where(s => s.parent_id == g.id).ToList();
-                        if (gChildList.Count > 0)
-                        {
-                            calcTest2(g, gChildList, returnlist, sockoccupyList);
-                            //如果是自制,则考虑自制够不够
-                            if (g.erp_cls == 1)
-                            {
-                                foreach (var cc in gChildList)
-                                {
-                                    //如果子物料是BOM,则当前物料的可制数量应该是子物料的库存加子物料的可制除以子物料的使用量
-                                    if (returnlist.Where(s => s.parent_id == cc.id).Count() > 0)
-                                    {
-                                        cc.kz = Math.Floor((cc.sqty + cc.kz) / g.qty);
-                                    }
-                                }
-                                g.kz = gChildList.Min(s => s.kz);//得到最小可制数量。
-                                
-                                //todo:如果是群组替代,可制数量应该跟随着主料来,不应该受限于最小可制单元。
-                                g.stock_state = gChildList.Max(s => s.stock_state);
-                                if (g.lack_qty <= g.kz)
-                                {
-                                    g.stock_state = 2;
-                                    boolCount++;
-                                }
-                            }
-                        }
-                        else
-                        {
-                            g.kz = Math.Floor(g.sqty / g.qty);//自己不是BOM的情况下,算一下自己可制父级可以制造多少个,这个可制只是基于父级BOM才用来运算。
-                            //todo:申老师说,如果是苏州工厂,原材料有可能也是自制的。
-                            //所以这里在计算时,还可以直接拿缺料数量,去丢给苏州计算方法,得出原材料的库存加可制。
-                        }
-                    }
-                    else
-                    {
-                        boolCount++;
-                    }*/
-                }
-
-                /*if (boolCount == group.Count())
-                {
-                    //如果检查集合满足条数与群组里的物料条数相同,则代表这个群组的数量是满足的。
-                    group.ForEach(s =>
-                    {
-                        s.is_show = true;
-                    });
-                    break;//如果已经找到合适的替代群组关系,并且都不需要采购,则直接不继续检查了。
-                }*/
-            }
-        }
-
-        /// <summary>
-        /// 根据每个物料来实时计算占用情况
-        /// </summary>
-        /// <param name="item"></param>
-        /// <param name="sockoccupyList"></param>
-        public void Calczykc(BomChildExamineDto item, BomChildExamineDto parent, List<ic_item_stockoccupy> sockoccupyList)
-        {
-            //找到当前物料的占用记录
-            var itemSockoccupy = sockoccupyList.Where(s => s.icitem_id == item.item_id).ToList();
-            //计算库存减去占用
-            item.sqty -= itemSockoccupy.Sum(s => s.quantity);
-            //如果库存
-            item.sqty = item.sqty < 0 ? 0 : item.sqty;
-            if (parent.stock_state == 1 || parent.stock_state == -1)
-            {
-                item.stock_state = parent.stock_state;
-                item.lack_qty = 0;
-            }
-            else
-            {
-                //判断缺料数量
-                item.lack_qty = parent.lack_qty * item.qty - item.sqty;
-                item.lack_qty = item.lack_qty < 0 ? 0 : item.lack_qty;
-                //判断状态
-                item.stock_state = item.lack_qty > 0 ? 0 : 1;
-            }
-        }
-
-        #region 替代检查第一版,屏蔽
-        /*/// <summary>
-        /// 替代关系检查计算
-        /// </summary>
-        public void CalcIcitemSubstitute(List<BomChildExamineDto> returnlist, int count)
-        {
-            returnlist = returnlist.OrderBy(s => s.num).ToList();
-            //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
-            //2.替代策略和替代方式,影响到的是甲乙组概念,替代按主料有限,取代按组的优先级。A与B的替代,则A和B各自会存在一个组。
-            List<long> calcIds = new List<long>();
-            //先处理下最顶级的产品需要数量
-            returnlist[0].needCount = returnlist[0].qty * count;
-            returnlist[0].satisfyNum = returnlist[0].sqty;
-            returnlist[0].lack_qty = returnlist[0].needCount - returnlist[0].satisfyNum;
-            returnlist[0].is_show = true;
-            foreach (var item in returnlist)
-            {
-                //循环平铺整个资源检查的物料库存情况、缺料情况
-                CaclMaterialShortage(returnlist, item, count);
-            }
-            foreach (var item in returnlist)
-            {
-                //替代件不计算,替代件通过标准件的替代关系,去计算需要使用哪些物料
-                if (item.type == 1)
-                {
-                    continue;
-                }
-                CaclBomChildUseShortage(returnlist, item);
-            }
-        }
-
-        /// <summary>
-        /// 物料计算
-        /// </summary>
-        /// <param name="returnlist"></param>
-        /// <param name="item"></param>
-        /// <param name="count"></param>
-        public void CaclBomChildUseShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item)
-        {
-            //判断是否是BOM,如果是BOM,还需要向下展开
-            var bomchild = returnlist.Where(s => s.parent_id == item.id).ToList();
-            if (bomchild.Count > 0)
-            {
-                foreach (var child in bomchild)
-                {
-                    CaclBomChildUseShortage(returnlist, item);
-                    //取子级的最高状态
-                    item.stock_state = bomchild.Max(s => s.stock_state);
-                    item.kitting_time = bomchild.Max(s => s.kitting_time);
-                }
-            }
-            //var tolist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num).ToList();
-            //有替代关系
-            if (item.haveicsubs == 1)
-            {
-                //首先判断标准件库存是否满足。
-                //如果是BOM,也需要向下展开,看子物料是否满足。
-                //不满足的情况下,则需要展开替代关系,根据替代策略和替代方式,来判定替代件的库存。
-                //假设子BOM有替代关系,则子BOM的子物料,也是有替代关系存在的,需要展开来看。
-                //1.假设标准件库存满足,则不计算替代件关系。
-                //2.如果标准件不满足,则替代件开始计算并展示。
-                //注意:不管是否需要替代件,标准件都需要展开。没有使用到的物料,定义为无需求。如果子BOM库存足够,则不需要显示子物料和替代关系。
-                var sublist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num && s.level == item.level).OrderBy(c => c.substitute_all_num).ToList();
-                //sublist找出当前含替代关系的标准件和替代件。
-                switch (item.substitute_strategy)
-                {
-                    case 0://整批
-                        break;
-                    case 1://混用
-                        break;
-                    case 2://整批加混用
-                        break;
-                }
-
-                
-                
-
-                if (item.substitute_mode == 0)
-                {
-                    //替代
-                }
-                else
-                {
-                    //取代
-                }
-            }
-            else//无替代关系
-            {
-                if (item.stock_state==0)
-                {
-                    item.use_qty = item.needCount;
-                    item.is_show = true;
-                }
-                else if (item.stock_state == 1)
-                {
-                    item.use_qty = item.sqty;
-                    // 缺料数量 item.lack_qty
-                    // 使用数量将库存全部使用了 item.use_qty = item.sqty;
-                    if (item.erp_cls == 2 || item.erp_cls == 3)
-                    {
-                        //委外、外购
-                        //生成委外工单、采购申请单
-                        //得到单据到货时间。
-                        //todo:初步设置为7天到货期,后期根据实际业务来补充修改。
-                        item.kitting_time = DateTime.Now.AddDays(7);
-                        item.stock_state = 2;
-                    }
-                    else if (item.erp_cls == 1)
-                    {
-                        //自制
-                        //调用产能计算,得到物料自制后的齐套时间。
-                        //todo:初步设置为7天完成,等沟通调用方法,来修改此处。
-                        item.kitting_time = DateTime.Now.AddDays(7);
-                        item.stock_state = 3;
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// 平铺物料缺料情况,展示所有主料+替代料的库存情况、缺料情况---需要修改成  库存情况、占用情况
-        /// </summary>
-        /// <param name="returnlist"></param>
-        /// <param name="item"></param>
-        /// <param name="count"></param>
-        public void CaclMaterialShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item, int count)
-        {
-            var parent = returnlist.Find(s => s.id == item.parent_id);
-            //当前物料总共需要数量
-            item.needCount = parent.needCount * item.qty;
-            //当前库存可以满足的数量
-            item.satisfyNum = item.sqty;
-            //总需要数量减去库存量,得出缺料数量
-            item.lack_qty = item.needCount - item.satisfyNum;
-            //如果不满足,计算子物料,或者计算替代料
-            if (item.lack_qty < 0)
-            {
-                //库存满足
-                item.stock_state = 0;
-                item.lack_qty = 0;
-            }
-            else
-            {
-                //找出自己的子集,存在子集则是BOM,不存在子集,则自己非BOM。
-                var childList = returnlist.Where(s => s.parent_id == item.id && s.type == item.type).ToList();
-                if (childList.Count > 0)
-                {
-                    //自己是BOM
-                    decimal kz = 0;//当前BOM可制数量
-                    foreach (var child in childList)
-                    {
-                        //循环子集判断库存
-                        CaclMaterialShortage(returnlist, child, count);
-                        kz = kz > ((child.sqty+ child.kz) / child.qty) ? Math.Floor((child.sqty + child.kz) / child.qty) : kz;
-                    }
-                    //向下取整
-                    item.kz =Math.Floor(kz);
-                }
-                else
-                {
-                    //原材料没有可制数量。
-                    item.kz = 0;
-                    item.stock_state = 1;
-                }
-            }
-        }*/
-        #endregion
-
         /// <summary>
         /// 根据物料id获取物料4个提前期
         /// </summary>