Murphy 3 vuotta sitten
vanhempi
commit
df7e8b9d5a

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

@@ -139,6 +139,11 @@ namespace Business.ResourceExamineManagement.Dto
         /// </summary>
         public decimal make_qty { get; set; }
 
+        /// <summary>
+        /// 委外数量
+        /// </summary>
+        public decimal Subcontracting_qty { get; set; }
+
         /// <summary>
         /// 齐套时间
         /// </summary>
@@ -214,6 +219,11 @@ namespace Business.ResourceExamineManagement.Dto
         /// </summary>
         public int stock_state { get; set; }
 
+        /// <summary>
+        /// 物料状态--0.缺料 1.充足 2.可制,时间满足 3.可制,时间不满足 4.采购 5.委外
+        /// </summary>
+        public int group_state { get; set; }
+
         /// <summary>
         /// 满足量
         /// </summary>

+ 16 - 3
MicroServices/Business/Business.Application.Contracts/ResourceExamineManagement/Dto/PschedDto.cs

@@ -10,11 +10,24 @@ namespace Business.ResourceExamineManagement.Dto
     public class PschedDto
     {
         /// <summary>
-        /// 建议交期
+        /// 最早开工时间
         /// </summary>
-        public DateTime suggestdate { get; set; }
+        public DateTime EarliestTimes { get; set; }
 
-        public int count { get; set; }
+        /// <summary>
+        /// 最晚开工时间
+        /// </summary>
+        public DateTime LatestTimes { get; set; }
+
+        /// <summary>
+        /// 物料齐套时间
+        /// </summary>
+        public DateTime KittingTimes { get; set; }
+
+        /// <summary>
+        /// 替代关系展开
+        /// </summary>
+        public List<BomChildExamineDto> substitutes  { get; set; }
 
     }
 }

+ 366 - 99
MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs

@@ -47,6 +47,8 @@ using System.Collections;
 using System.Data.SqlTypes;
 using Microsoft.EntityFrameworkCore.Diagnostics;
 using Hangfire.Server;
+using WkHtmlToPdfDotNet;
+using Microsoft.EntityFrameworkCore.Migrations.Operations;
 
 namespace Business.ResourceExamineManagement
 {
@@ -296,9 +298,9 @@ namespace Business.ResourceExamineManagement
             _srm_po_list = srm_po_list;
             _crm_seorder = crm_seorder;
             _crm_seorderentry = crm_seorderentry;
-            _srm_po_occupy= srm_po_occupy;
-            _ic_item_pur= ic_item_pur;
-            _ic_plan= ic_plan;
+            _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;
@@ -323,9 +325,9 @@ namespace Business.ResourceExamineManagement
             _mysql_mes_tech_process = mysql_mes_tech_process;
             _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;
+            _mysql_srm_po_occupy = mysql_srm_po_occupy;
+            _mysql_ic_item_pur = mysql_ic_item_pur;
+            _mysql_ic_plan = mysql_ic_plan;
         }
 
         /// <summary>
@@ -393,6 +395,15 @@ namespace Business.ResourceExamineManagement
             SnowFlake snow = new SnowFlake();
             long bangid = snow.NextId();
 
+            //获取订单数据
+            crm_seorder sorder = _mysql_crm_seorder.GetAsync(p => p.Id == input.sorderId && p.IsDeleted == false).Result;
+            if (sorder == null)
+            {
+                throw new NotImplementedException("订单数据不存在!");
+            }
+            //获取订单行数据
+            List<crm_seorderentry> sentrys = _mysql_crm_seorderentry.GetListAsync(p => p.seorder_id == input.sorderId && p.IsDeleted == false).Result;
+
             string bom_number = "BOM00042070";
             int packages = 1000;
 
@@ -430,7 +441,9 @@ namespace Business.ResourceExamineManagement
             //产能检查
             await ProductiveExamine(bom_number, packages);
             //var id = Save(input.tenantId, input.factoryId);
-            //await GenerateMorder(id);
+            //await GenerateMorder(1736470478942093312);
+            //var dateTime = DateTime.Parse("2021-09-03");
+            //await CheckMorder("9.1.03.01.0541", 1000, dateTime, 1736470478942093312);
             return null;
             throw new NotImplementedException();
         }
@@ -724,13 +737,13 @@ namespace Business.ResourceExamineManagement
         /// <param name="DeliverDate">交付日期</param>
         /// <param name="seorderentry_id">销售订单子表ID</param>
         /// <returns></returns>
-        public async Task GenerateMorder(long seorderentry_id)
+        public async Task GenerateMorder(crm_seorderentry seorderentry)
         {
             //1.库存、在制工单检查完成后 当前BOM需要自制时 产生工单。
 
             //2.每一个销售订单行对应一个工单。
             //查询销售订单子表数据
-            var seorderentry = await _mysql_crm_seorderentry.FindAsync(x => x.Id == seorderentry_id);
+            //var seorderentry = await _mysql_crm_seorderentry.FindAsync(x => x.Id == seorderentry_id);
             //获取销售订单信息
             var seorder = await _mysql_crm_seorder.FindAsync(x => x.Id == seorderentry.seorder_id);
             //物料BOM
@@ -833,23 +846,23 @@ namespace Business.ResourceExamineManagement
         /// <param name="DeliverDate">交付日期</param>
         /// <param name="seorderentry_id">销售订单子表ID</param>
         /// <returns></returns>
-        public async Task<bool> CheckMorder(string bomNumber, decimal? Quantity, DateTime DeliverDate, long seorderentry_id)
+        public async Task<bool> CheckMorder(string bomNumber, decimal? Quantity, DateTime DeliverDate, crm_seorderentry seorderentry)
         {
-            if (string.IsNullOrEmpty(bomNumber) || Quantity != null)
+            if (string.IsNullOrEmpty(bomNumber) || Quantity == null)
             {
                 //TODO:入参异常;
                 throw new NotImplementedException("BOM编码或需求数量不能为空!");
             }
             //获取销售订单信息
             //var seorder = await _crm_seorder.FindAsync(x => x.Id == OrderId);
-            var seorderentry = await _mysql_crm_seorderentry.FindAsync(x => x.Id == seorderentry_id);
+            //var seorderentry = await _mysql_crm_seorderentry.FindAsync(x => x.Id == seorderentry_id);
             //根据Bom编码查询出对应工单并且状态不为完成、关闭,非委外工单。
             //TODO:工单类型;
             var morderList = await _mes_morder.GetManyByCondition(x => x.bom_number == bomNumber && (x.morder_state != "完成" || x.morder_state != "关闭"
             && x.morder_icitem_type != "相关委外工单") && x.IsDeleted == false && x.tenant_id == seorderentry.tenant_id);
 
             //获取物料详情
-            var mysql_ic_item = await _mysql_ic_item.FindAsync(x => x.number == bomNumber && x.tenant_id == seorderentry.tenant_id);
+            var ic_item = _ic_item.GetManyByCondition(x => x.number == seorderentry.item_number && x.tenant_id == seorderentry.tenant_id).Result.FirstOrDefault();
 
             //工单已被占用后要与占用表关联查询...减去占用量后 剩下生产数量可供下个销售工单使用。
             var mes_mooccupyList = await _mes_mooccupy.GetManyByCondition(x => x.moo_state == 1 && x.IsDeleted == false && x.tenant_id == seorderentry.tenant_id);
@@ -863,7 +876,7 @@ namespace Business.ResourceExamineManagement
                 //存在此数据满足当前BOM交付找到最早日期工单,则返回无需后续继续检查。
                 var morder = morderDataList.OrderByDescending(x => x.planner_end_date).FirstOrDefault();
                 var mooccupies = mes_mooccupyList.Where(x => x.moo_moid == morder.Id).ToList();
-                var mes_Mooccupy = GetMooccupies(seorderentry, mysql_ic_item, morder, mooccupies);
+                var mes_Mooccupy = GetMooccupies(seorderentry, ic_item, morder, mooccupies);
                 await _mes_mooccupy.InsertOne(mes_Mooccupy);
             }
             else
@@ -882,7 +895,7 @@ namespace Business.ResourceExamineManagement
                 {
                     //查询出工单已占用总数量
                     var mooccupies = mes_mooccupyList.Where(x => x.moo_moid == item.Id).ToList();
-                    var mes_Mooccupy = GetMooccupies(seorderentry, mysql_ic_item, item, mooccupies);
+                    var mes_Mooccupy = GetMooccupies(seorderentry, ic_item, item, mooccupies);
                     mes_Mooccupies.Add(mes_Mooccupy);
                     //需求数量-占用量后小于或等于0 停止循环占用工单
                     if (number - mes_Mooccupy.moo_qty <= 0)
@@ -901,7 +914,7 @@ namespace Business.ResourceExamineManagement
         /// <param name="item">工单表</param>
         /// <param name="mes_mooccupy">占用工单表</param>
         /// <returns></returns>
-        public mes_mooccupy GetMooccupies(crm_seorderentry seorderentry, ic_item mysql_ic_item, mes_morder item, List<mes_mooccupy> mes_mooccupy)
+        public mes_mooccupy GetMooccupies(crm_seorderentry seorderentry, ic_item ic_item, mes_morder item, List<mes_mooccupy> mes_mooccupy)
         {
             decimal? Sumqty = 0;
             if (mes_mooccupy.Count > 0)
@@ -915,9 +928,9 @@ namespace Business.ResourceExamineManagement
             mes_Mooccupy.moo_id_billid = seorderentry.seorder_id;//销售订单ID
             mes_Mooccupy.fbill_no = seorderentry.bill_no;//销售订单号
             mes_Mooccupy.fentry_id = seorderentry.entry_seq.Value;//销售订单行
-            mes_Mooccupy.fitem_name = mysql_ic_item.name;//物料名称
-            mes_Mooccupy.fitem_number = mysql_ic_item.number;
-            mes_Mooccupy.fmodel = mysql_ic_item.model;//规格型号
+            mes_Mooccupy.fitem_name = ic_item.name;//物料名称
+            mes_Mooccupy.fitem_number = ic_item.number;
+            mes_Mooccupy.fmodel = ic_item.model;//规格型号
             mes_Mooccupy.moo_moid = item.Id;
             mes_Mooccupy.moo_mo = item.morder_no;
             //占用量=生产计划数量-入库数量-已被占用数量
@@ -1205,7 +1218,7 @@ namespace Business.ResourceExamineManagement
             List<long> icitemIds = returnlist.Select(c => c.item_id).ToList();
             var stocklist = _ic_item_stock.GetManyByCondition(p => p.factory_id == factoryid && icitemIds.Contains(p.icitem_id)).Result;
             //取当前订单的物料库存占用记录
-            var occupylist = _ic_item_stockoccupy.GetManyByCondition(p => p.bang_id == bangid && p.order_id == orderid).Result;
+            //var occupylist = _ic_item_stockoccupy.GetManyByCondition(p => p.bang_id == bangid && p.order_id == orderid).Result;
             //计算剩余库存
             foreach (var item in returnlist)
             {
@@ -1217,84 +1230,314 @@ namespace Business.ResourceExamineManagement
                 //当前物料的库存数量
                 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);
+                //decimal otherStockQty = occupylist.Where(s => s.icitem_id == item.item_id).Sum(p => p.quantity);
                 //当前订单行物料库存情况
-                item.sqty = stockQty - otherStockQty;
+                //item.sqty = stockQty - otherStockQty;
+                item.sqty = stockQty;
             }
         }
 
 
-
-        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid)
+        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid, decimal count)
         {
             //占用情况
-            var occupylist = _ic_item_stockoccupy.GetManyByCondition(p => p.icitem_id == bangid && p.order_id == orderid).Result;
+            List<ic_item_stockoccupy> sklist = new List<ic_item_stockoccupy>();
+            //var occupylist = _ic_item_stockoccupy.GetManyByCondition(p => p.icitem_id == bangid && p.order_id == orderid).Result;
 
             //第一级
+            returnlist = returnlist.OrderBy(s => s.num).ToList();
             var childList = returnlist.Where(s => s.parent_id == returnlist[0].id && s.type == 0).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].sqty;
+            /*if (returnlist[0].lack_qty < 0)
+            {
+                //库存满足
+                returnlist[0].stock_state = 1;
+                returnlist[0].lack_qty = 0;
+            }
+            else
+            {
+                returnlist[0].stock_state = 0;
+            }*/
+            foreach (var item in returnlist)
+            {
+                if (item.level == 1)
+                {
+                    continue;
+                }
+                //循环平铺整个资源检查的物料库存情况、缺料情况,子集缺料需要用父级缺料*子集使用数量-
+                CaclMaterialShortage(returnlist, item, count);
+            }
+
             //这是从上往下展开计算缺料和可制
-            calcTest2(returnlist[0], childList, returnlist, occupylist);
-            returnlist[0].kz = childList.Min(s => s.kz);//得到最小可制数量。
+            calcTest2(returnlist[0], childList, returnlist, sklist);
+            //returnlist[0].kz = childList.Min(s => s.kz);//得到最小可制数量。
             //再加个循环,来根据替代关系里的检查结果,根据规则明确使用和生成占用关系。
+
+
             foreach (var item in childList)
             {
-                //提取群组关系
-                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();
-                int idx;
-                List<BomChildExamineDto> select = new List<BomChildExamineDto>();
-                switch (item.substitute_strategy)
+                if (item.haveicsubs == 1)
                 {
-                    case 0://整批
-                           //循环检查哪一批可以直接使用,不需要采购
-                        for (idx = 0; idx < 99; idx++)
-                        {
-                            var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
-                            if (list.Any())
-                            {
-                                if (list.Where(s => s.stock_state != 1 && s.stock_state != 2 && s.stock_state != 3).Count() == 0)
-                                {
-                                    //只满足充足或可制
-                                    //无缺料情况
-                                    select = list;
-                                    break;
-                                }
-                                idx++;
-                            }
-                            else
-                            {
-                                idx = 99;
-                            }
-                        }
-                        //如果都需要采购的情况下,则默认使用优先级最高的
-                        if (select.Count() == 0)
-                        {
-                            //如果为空,则默认使用优先级为0的集合作为替代关系
-                            select = sublist.Where(s => s.substitute_all_num == 0).ToList();
-                            select.ForEach(s => { s.is_use = true; s.stock_state = 4; });
-                        }
+                    //如果有替代关系,根据群组来明确使用哪个群组的替代料。按整批和混用逻辑来算
+                    // 如果有群组替代,就移除掉被检查过的记录 item.icitem_ids
+                    CalcStrategy(item, returnlist, bangid, sklist);
+                }
+                else
+                {
+                    //直接占用库存,缺料就生成采购
+                }
+            }
+        }
+
+
+        //平铺每个物料需要总数
+        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;
+            }*/
+        }
+
+        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;
+        }
+
+        public void CalcStrategy(BomChildExamineDto item, List<BomChildExamineDto> returnlist, long bangid, List<ic_item_stockoccupy> sklist)
+        {
+            //提取群组关系
+            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(sublist, returnlist, sklist, select, bangid, parent);
+                    break;
+                case 1://混用
+                    MixedUse(sublist, returnlist, sklist, bangid, parent);
+                    break;
+                case 2://整批加混用
+                    WholeBatchCheck(sublist, returnlist, sklist, select);
+                    if (select.Count() == 0)
+                    {
+                        //走混用
+                        MixedUse(sublist, returnlist, sklist, bangid, parent);
+                    }
+                    else
+                    {
+                        //走整批
+                        WholeBatch(sublist, returnlist, sklist, select, bangid, parent);
+                    }
+                    break;
+            }
+        }
+        //整批判断
+        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);
+                    }
+                    if (list.Where(s => s.stock_state != 1).Count() == 0)
+                    {
+                        //只满足充足或可制
+                        //无缺料情况
+                        select = list;
+                        select.ForEach(s => { s.is_use = true; });
                         break;
-                    case 1://混用
-                        for (idx = 0; idx < 99; idx++)
+                    }
+                    idx++;
+                }
+                else
+                {
+                    idx = 99;
+                }
+            }
+
+        }
+        //整批占用
+        public void WholeBatch(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, List<BomChildExamineDto> select, long bangid, BomChildExamineDto parent)
+        {
+            if (select.Count() == 0)
+            {
+                //如果为空,则默认使用优先级为0的集合作为替代关系
+                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;
+                if (slt.lack_qty > 0)
+                {
+                    itemStockoccupyDto.quantity = slt.sqty;
+                    //库存不够的时候,根据属性生成采购和委外。
+                    var lack_qty = slt.lack_qty - itemStockoccupyDto.quantity;
+                    if (slt.erp_cls == 1)
+                    {
+                        slt.make_qty = lack_qty;
+                        /*var childList = returnlist.Where(s => s.parent_id == slt.id).ToList();
+                        if (childList.Count() > 0)
                         {
-                            var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
-                            if (list.Any())
-                            {
-                                foreach (var hy in list)
-                                {
-                                    //如果自己是可制,并且有子集,则取出自己父级的缺料数量和可制数量,使用掉自己的末级。
+                            CalcStrategy(slt, returnlist, bangid, sklist);
+                        }*/
+                    }
+                    else if (slt.erp_cls == 2)
+                    {
+                        //生成委外工单
+                        slt.Subcontracting_qty = lack_qty;
+                    }
+                    else if (slt.erp_cls == 3)
+                    {
+                        //生成采购订单
+                        slt.purchase_qty = lack_qty;
+                    }
+                }
+                else
+                {
+                    itemStockoccupyDto.quantity = slt.needCount;
+                    if (parent != null)
+                    {   //如果不缺料的情况下,则占用掉父级缺料乘以当前子集使用料数量
+                        itemStockoccupyDto.quantity = parent.lack_qty * slt.qty - slt.sqty;
+                    }
+                }
+                sklist.Add(itemStockoccupyDto);
+            }
 
-                                }
-                                idx++;
-                            }
+        }
+
+        //混用占用数据
+        public void MixedUse(List<BomChildExamineDto> sublist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sklist, long bangid, BomChildExamineDto parent)
+        {
+
+            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 = 9999999;
+                    foreach (var hy in list)
+                    {
+                        //混用先使用掉当前要用的数量
+                        //得到库存最小数量,去占用,然后剩余的丢第二个循环里去占用。
+                        decimal make = hy.sqty / hy.qty;
+                        if (minMake > make)
+                        {
+                            minMake = make;
                         }
-                        break;
-                    case 2://整批加混用
-                        break;
+                    }
+                    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)
+                    {
+                        ic_item_stockoccupy itemStockoccupyDto = new ic_item_stockoccupy();
+                        itemStockoccupyDto.bang_id = bangid;
+                        itemStockoccupyDto.icitem_id = zy.item_id;
+                        itemStockoccupyDto.quantity = use_p_num * zy.qty; ;
+                    }
+                    idx++;
                 }
             }
         }
 
 
+        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)
+            {
+                //根据最小颗粒度
+            }
+        }
+
+        //计算物料是否缺料
         public void calcTest2(BomChildExamineDto parent, List<BomChildExamineDto> bzlist, List<BomChildExamineDto> returnlist, List<ic_item_stockoccupy> sockoccupyList)
         {
             //从第二级开始循环
@@ -1310,7 +1553,22 @@ namespace Business.ResourceExamineManagement
                     //循环计算群组,看哪个群组满足要求,然后使用此群组,将群组的库存和子物料占用掉。
                     //计算此次群组是否有符合
                     MaterialCalc(sublist, returnlist, sockoccupyList);
-
+                }
+                else
+                {
+                    //根据占用情况计算库存
+                    Calczykc(item, sockoccupyList);
+                    //如果有子集,则丢入循环,判断下库存可制等信息。
+                    calcTest2(item, childList, returnlist, sockoccupyList);
+                    /*item.kz = childList.Min(s => s.kz);
+                    if (item.kz >= item.lack_qty)
+                    {
+                        item.stock_state = 3;
+                    }
+                    else
+                    {
+                        item.stock_state = 0;
+                    }*/
                 }
             }
         }
@@ -1325,14 +1583,14 @@ namespace Business.ResourceExamineManagement
             for (int i = 0; i <= maxIdx; i++)
             {
                 var group = sublist.Where(s => s.substitute_all_num == i).ToList();
-                int boolCount = 0;//代表某一颗物料无需采购,可以自制,则集合+1。
+                // int boolCount = 0;//代表某一颗物料无需采购,可以自制,则集合+1。
 
                 //如果替代料库存不够,但是可制够,则也考虑使用优先级最高
                 foreach (var g in group)
                 {
                     //根据占用情况计算库存
                     Calczykc(g, sockoccupyList);
-                    if (g.stock_state != 1)
+                    /*if (g.stock_state != 1)
                     {
                         //判断此料是否BOM,如果是BOM,就考虑自制是否足够,此处递归检查子集
                         var gChildList = returnlist.Where(s => s.parent_id == g.id).ToList();
@@ -1342,10 +1600,19 @@ namespace Business.ResourceExamineManagement
                             //如果是自制,则考虑自制够不够
                             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)
+                                if (g.lack_qty <= g.kz)
                                 {
                                     g.stock_state = 2;
                                     boolCount++;
@@ -1362,10 +1629,10 @@ namespace Business.ResourceExamineManagement
                     else
                     {
                         boolCount++;
-                    }
+                    }*/
                 }
 
-                if (boolCount == group.Count())
+                /*if (boolCount == group.Count())
                 {
                     //如果检查集合满足条数与群组里的物料条数相同,则代表这个群组的数量是满足的。
                     group.ForEach(s =>
@@ -1373,7 +1640,7 @@ namespace Business.ResourceExamineManagement
                         s.is_show = true;
                     });
                     break;//如果已经找到合适的替代群组关系,并且都不需要采购,则直接不继续检查了。
-                }
+                }*/
             }
         }
 
@@ -1565,22 +1832,22 @@ namespace Business.ResourceExamineManagement
         {
             //ToDo:企业Id
             ProjectionDefinitionBuilder<ic_factory_details> project = new ProjectionDefinitionBuilder<ic_factory_details>();
-            return _ic_factory_details.Find(p => returnlist.Select(x => x.item_id).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();
+            return _ic_factory_details.Find(p => returnlist.Select(x => x.item_id).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<BomChildExamineDto> returnlist, long tenantId,long factoryid)
+        private List<ic_item_pur> GetSupplier(List<BomChildExamineDto> returnlist, long tenantId, long factoryid)
         {
             //ToDo:企业Id
             return _ic_item_pur.Find(p => returnlist.Select(x => x.item_id).Contains(p.icitem_id) && p.tenant_id == tenantId && p.factory_id == factoryid && !p.IsDeleted).Result;
         }
 
         //根据物料id获取物料采购计划表
-        private List<ic_plan> GetICPlan(List<BomChildExamineDto> returnlist, long tenantId,long factoryid)
+        private List<ic_plan> GetICPlan(List<BomChildExamineDto> returnlist, long tenantId, long factoryid)
         {
-            return _ic_plan.Find(p => returnlist.Select(x => x.item_id).Contains(p.icitem_id) &&p.tenant_id==tenantId  && p.factory_id == factoryid && !p.IsDeleted).Result;
+            return _ic_plan.Find(p => returnlist.Select(x => x.item_id).Contains(p.icitem_id) && p.tenant_id == tenantId && p.factory_id == factoryid && !p.IsDeleted).Result;
         }
 
 
@@ -1594,11 +1861,11 @@ namespace Business.ResourceExamineManagement
         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) && p.tenant_id== tenantId && p.factory_id == factoryid && p.rarrdate >= DateTime.Now && p.rarrdate < deliveryDate && !p.IsDeleted).Result;
+            var po_list = _srm_po_list.Find(p => returnlist.Select(x => x.item_id).Contains(p.icitem_id) && 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, tenantId, factoryid);//提前期列表
             var supplierList = GetSupplier(returnlist, tenantId, factoryid);//供应商列表
-            var planList = GetICPlan(returnlist, tenantId,factoryid);//plan列表
+            var planList = GetICPlan(returnlist, tenantId, factoryid);//plan列表
             foreach (var item in returnlist)
             {
                 //缺料
@@ -1749,13 +2016,13 @@ namespace Business.ResourceExamineManagement
             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_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_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);//系统建议下单日期
@@ -1763,22 +2030,22 @@ namespace Business.ResourceExamineManagement
             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_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_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.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);//减去提前期
+            return deliveryDate.AddDays((double)totalLeadTime * -1);//减去提前期
         }
 
         // 生成订单编号 字母+年月日+8位随机数+时间戳