Przeglądaj źródła

替代料计算与调整

tangdi 3 lat temu
rodzic
commit
575cd82590

+ 16 - 2
MicroServices/Business/Business.Application.Contracts/ResourceExamineManagement/Dto/BomChildExamineDto.cs

@@ -210,7 +210,7 @@ namespace Business.ResourceExamineManagement.Dto
         public int substitute_mode { get; set; }
 
         /// <summary>
-        /// 物料状态--0.充足 1.缺料 2.可制,时间满足 3.可制,时间不满足 4.无需求
+        /// 物料状态--0.缺料 1.充足 2.可制,时间满足 3.可制,时间不满足 4.采购 5.委外
         /// </summary>
         public int stock_state { get; set; }
 
@@ -235,14 +235,28 @@ namespace Business.ResourceExamineManagement.Dto
         public decimal needCount { get; set; }
 
         /// <summary>
-        /// 使用数量
+        /// 使用数量(库存使用)
         /// </summary>
         public decimal use_qty { get; set; }
 
+        /// <summary>
+        /// 被父级可制占用,为了实现占用计算
+        /// </summary>
+        public decimal use_ParentItemOccupy { get; set; }
+
         /// <summary>
         /// 是否显示
         /// </summary>
         public bool is_show { get; set; }
 
+        /// <summary>
+        /// 是否使用此物料
+        /// </summary>
+        public bool is_use { get; set; }
+
+        /// <summary>
+        /// 计算时使用
+        /// </summary>
+        public decimal calc_use { get; set; }
     }
 }

+ 214 - 19
MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs

@@ -37,6 +37,9 @@ using System.Runtime.CompilerServices;
 using MongoDB.Driver;
 using Volo.Abp.Validation.Localization;
 using Hangfire.Annotations;
+using System.IO.Compression;
+using System.Collections;
+using System.Data.SqlTypes;
 
 namespace Business.ResourceExamineManagement
 {
@@ -694,11 +697,16 @@ namespace Business.ResourceExamineManagement
                                 var sadl = subdtllist.Where(s => s.substitute_allid == sal.Id).ToList();
                                 foreach (var dtl in sadl)
                                 {
-                                    if (dtl.ismain == 0)
+                                    if (dtl.ismain != 0)//替代关系里,已经将BOM料当成主料存放于替代群组里了。
                                     {
                                         //递归将替代关系组装出来。
                                         SubstitutePretreatment(sl, sal, dtl, item, returnlist, 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;//群组优先级
+                                    }
                                 }
                             }
                         }
@@ -719,7 +727,6 @@ namespace Business.ResourceExamineManagement
         /// <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层级dto,明细
             //如果dtl对应的icitem是BOM,还需要向下继续展开。
             var help = new SnowFlake();
 
@@ -743,8 +750,9 @@ namespace Business.ResourceExamineManagement
             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 = toDto.qty;
+            //dto.replace_amount = dtl.replace_amount.Value;
+            dto.qty = dtl.replace_amount.Value;
             dto.is_replace = 0;
             dto.haveicsubs = 0;
             dto.substitute_code = "";
@@ -802,10 +810,178 @@ namespace Business.ResourceExamineManagement
             }
         }
 
+        
+
+        public void calcTest(List<BomChildExamineDto> returnlist, long bangid, long orderid)
+        {
+            //占用情况
+            var occupylist = _ic_item_stockoccupy.GetManyByCondition(p => p.icitem_id == bangid && p.order_id == orderid).Result;
+
+            //第一级
+            var childList = returnlist.Where(s => s.parent_id == returnlist[0].id && s.type == 0).ToList();
+            //这是从上往下展开计算缺料和可制
+            calcTest2(returnlist[0], childList, returnlist, occupylist);
+            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)
+                {
+                    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; });
+                        }
+                        break;
+                    case 1://混用
+                        for (idx = 0; idx < 99; idx++)
+                        {
+                            var list = sublist.Where(s => s.substitute_all_num == idx).ToList();
+                            if (list.Any())
+                            {
+                                foreach (var hy in list)
+                                {
+                                    //如果自己是可制,并且有子集,则取出自己父级的缺料数量和可制数量,使用掉自己的末级。
+
+                                }
+                                idx++;
+                            }
+                        }
+                        break;
+                    case 2://整批加混用
+                        break;
+                }
+            }
+        }
+        
+
+        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).ToList();
+
+                //存在替代关系
+                if (item.haveicsubs == 1)
+                {
+                    //提取群组关系
+                    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();
+                    //循环计算群组,看哪个群组满足要求,然后使用此群组,将群组的库存和子物料占用掉。
+                    //计算此次群组是否有符合
+                    MaterialCalc(sublist, 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)
+                {
+                    //根据占用情况计算库存
+                    Calczykc(g, 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)
+                            {
+                                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;//如果已经找到合适的替代群组关系,并且都不需要采购,则直接不继续检查了。
+                }
+            }
+        }
+
+        //根据每个物料来实时计算占用情况
+        public void Calczykc(BomChildExamineDto item, 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;
+            //判断缺料数量
+            item.lack_qty = item.needCount - item.sqty;
+            //判断状态
+            item.stock_state = item.lack_qty > 0 ? 0 : 1;
+        }
+
+        #region 替代检查第一版,屏蔽
+        /*/// <summary>
         /// 替代关系检查计算
         /// </summary>
-        public void CalcIcitemSubstitute(List<BomChildExamineDto> returnlist,int count)
+        public void CalcIcitemSubstitute(List<BomChildExamineDto> returnlist, int count)
         {
             returnlist = returnlist.OrderBy(s => s.num).ToList();
             //1.如果主料够的时候,不需要显示替代料的平铺视图,如果主料不够,显示替代料的平铺视图。
@@ -819,7 +995,7 @@ namespace Business.ResourceExamineManagement
             foreach (var item in returnlist)
             {
                 //循环平铺整个资源检查的物料库存情况、缺料情况
-                CaclMaterialShortage(returnlist,item, count);
+                CaclMaterialShortage(returnlist, item, count);
             }
             foreach (var item in returnlist)
             {
@@ -841,15 +1017,18 @@ namespace Business.ResourceExamineManagement
         public void CaclBomChildUseShortage(List<BomChildExamineDto> returnlist, BomChildExamineDto item)
         {
             //判断是否是BOM,如果是BOM,还需要向下展开
-            var bomchild = returnlist.Where(s => s.parent_id == item.id && s.type == 0).ToList();
+            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();
+            //var tolist = returnlist.Where(s => s.parent_id == item.parent_id && s.num == item.num).ToList();
             //有替代关系
             if (item.haveicsubs == 1)
             {
@@ -859,12 +1038,21 @@ namespace Business.ResourceExamineManagement
                 //假设子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)
                 {
@@ -872,20 +1060,18 @@ namespace Business.ResourceExamineManagement
                 }
                 else { 
                     //取代
-
                 }
             }
-            else
+            else//无替代关系
             {
-                //无替代关系
                 if (item.stock_state==0)
                 {
                     item.use_qty = item.needCount;
                     item.is_show = true;
-                    item.stock_state = 0;
                 }
                 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)
@@ -895,6 +1081,7 @@ namespace Business.ResourceExamineManagement
                         //得到单据到货时间。
                         //todo:初步设置为7天到货期,后期根据实际业务来补充修改。
                         item.kitting_time = DateTime.Now.AddDays(7);
+                        item.stock_state = 2;
                     }
                     else if (item.erp_cls == 1)
                     {
@@ -902,13 +1089,14 @@ namespace Business.ResourceExamineManagement
                         //调用产能计算,得到物料自制后的齐套时间。
                         //todo:初步设置为7天完成,等沟通调用方法,来修改此处。
                         item.kitting_time = DateTime.Now.AddDays(7);
+                        item.stock_state = 3;
                     }
                 }
             }
         }
 
         /// <summary>
-        /// 平铺物料缺料情况,展示所有主料+替代料的库存情况、缺料情况
+        /// 平铺物料缺料情况,展示所有主料+替代料的库存情况、缺料情况---需要修改成  库存情况、占用情况
         /// </summary>
         /// <param name="returnlist"></param>
         /// <param name="item"></param>
@@ -918,9 +1106,10 @@ namespace Business.ResourceExamineManagement
             var parent = returnlist.Find(s => s.id == item.parent_id);
             //当前物料总共需要数量
             item.needCount = parent.needCount * item.qty;
-            item.satisfyNum = item.sqty;//5
+            //当前库存可以满足的数量
+            item.satisfyNum = item.sqty;
+            //总需要数量减去库存量,得出缺料数量
             item.lack_qty = item.needCount - item.satisfyNum;
-
             //如果不满足,计算子物料,或者计算替代料
             if (item.lack_qty < 0)
             {
@@ -935,18 +1124,24 @@ namespace Business.ResourceExamineManagement
                 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
     }
 }