Prechádzať zdrojové kódy

Merge branch 'dev' of http://123.60.180.165:4647/ZZYDOP/DOPCore into dev

# Conflicts:
#	MicroServices/Business/Business.Application/ResourceExamineManagement/CalcBomViewAppService.cs
#	MicroServices/Business/Business.Domain/MongoDB/MES/IC/mo_ic_item.cs
#	MicroServices/Business/Business.Domain/StructuredDB/MES/IC/ic_item.cs
tangdi 2 rokov pred
rodič
commit
9ed658d432
48 zmenil súbory, kde vykonal 2930 pridanie a 1663 odobranie
  1. 4 0
      MicroServices/Business/Business.Application.Contracts/Business.Application.Contracts.csproj
  2. 44 2
      MicroServices/Business/Business.Application.Contracts/ReplenishmentManagement/IReplenishmentAppService.cs
  3. 0 20
      MicroServices/Business/Business.Application.Contracts/SaleForecast/IAnnualProductionOutlineAppService.cs
  4. 0 38
      MicroServices/Business/Business.Application.Contracts/SaleForecast/IMonthlyCapacityLoadAppService.cs
  5. 901 32
      MicroServices/Business/Business.Application/ReplenishmentManagement/ReplenishmentAppService.cs
  6. 20 2
      MicroServices/Business/Business.Application/ResourceExamineManagement/CalcBomViewAppService.cs
  7. 1 0
      MicroServices/Business/Business.Application/ResourceExamineManagement/MorderAppService.cs
  8. 73 70
      MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs
  9. 16 1
      MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs
  10. 0 308
      MicroServices/Business/Business.Application/SaleForecastManagement/AnnualProductionOutlineAppService.cs
  11. 0 1034
      MicroServices/Business/Business.Application/SaleForecastManagement/MonthlyCapacityLoadAppService.cs
  12. 3 1
      MicroServices/Business/Business.Domain/MongoDB/MES/IC/mo_ic_item.cs
  13. 3 1
      MicroServices/Business/Business.Domain/StructuredDB/MES/IC/ic_item.cs
  14. 2 2
      MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentAnnualProduction.cs
  15. 176 0
      MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentMonthPlan.cs
  16. 3 3
      MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentROP.cs
  17. 3 3
      MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentServiceLevel.cs
  18. 193 0
      MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentWeekPlan.cs
  19. 2 2
      MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/BusinessDbContextModelCreatingExtensions.cs
  20. 4 3
      MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/DOP/BusinessDbContext.cs
  21. 0 47
      MicroServices/Business/Business.HttpApi/Controllers/AnnualProductionOutlineController.cs
  22. 0 73
      MicroServices/Business/Business.HttpApi/Controllers/MonthlyCapacityLoadController.cs
  23. 70 20
      MicroServices/Business/Business.HttpApi/Controllers/ReplenishmentController.cs
  24. 60 0
      MicroServices/Business/QuartzSettings/logs/logs.txt
  25. 1 1
      MicroServices/Business/QuartzSettings/task_job.json
  26. 51 0
      MicroServices/DopInterfacePlatform/ClientIpCheckActionFilter.cs
  27. 40 0
      MicroServices/DopInterfacePlatform/Controllers/TokenController.cs
  28. 73 0
      MicroServices/DopInterfacePlatform/Controllers/WeatherForecastController.cs
  29. 23 0
      MicroServices/DopInterfacePlatform/DopInterfacePlatform.csproj
  30. 8 0
      MicroServices/DopInterfacePlatform/DopInterfacePlatform.csproj.user
  31. 25 0
      MicroServices/DopInterfacePlatform/DopInterfacePlatform.sln
  32. 14 0
      MicroServices/DopInterfacePlatform/DopInterfacePlatformContext.cs
  33. 49 0
      MicroServices/DopInterfacePlatform/Entity/InterfacePlatformLog.cs
  34. 9 0
      MicroServices/DopInterfacePlatform/Interface/IJwtService.cs
  35. 55 0
      MicroServices/DopInterfacePlatform/IpWhiteListMiddleware.cs
  36. 28 0
      MicroServices/DopInterfacePlatform/JWTExtensions.cs
  37. 25 0
      MicroServices/DopInterfacePlatform/JwtOptions.cs
  38. 108 0
      MicroServices/DopInterfacePlatform/LogFilter.cs
  39. 65 0
      MicroServices/DopInterfacePlatform/Program.cs
  40. 21 0
      MicroServices/DopInterfacePlatform/Properties/PublishProfiles/FolderProfile.pubxml
  41. 11 0
      MicroServices/DopInterfacePlatform/Properties/PublishProfiles/FolderProfile.pubxml.user
  42. 31 0
      MicroServices/DopInterfacePlatform/Properties/launchSettings.json
  43. 21 0
      MicroServices/DopInterfacePlatform/Service/JwtService.cs
  44. 610 0
      MicroServices/DopInterfacePlatform/StringHelper.cs
  45. 44 0
      MicroServices/DopInterfacePlatform/SwaggerGenOptionsExtensions.cs
  46. 13 0
      MicroServices/DopInterfacePlatform/WeatherForecast.cs
  47. 8 0
      MicroServices/DopInterfacePlatform/appsettings.Development.json
  48. 19 0
      MicroServices/DopInterfacePlatform/appsettings.json

+ 4 - 0
MicroServices/Business/Business.Application.Contracts/Business.Application.Contracts.csproj

@@ -41,4 +41,8 @@
     <ProjectReference Include="..\Business.Domain\Business.Domain.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="SaleForecast\" />
+  </ItemGroup>
+
 </Project>

+ 44 - 2
MicroServices/Business/Business.Application.Contracts/ReplenishmentManagement/IReplenishmentAppService.cs

@@ -1,4 +1,5 @@
 using Business.Dto;
+using Microsoft.AspNetCore.Mvc;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -9,18 +10,59 @@ namespace Business.ReplenishmentManagement
 {
     public interface IReplenishmentAppService
     {
+        /// <summary>
+        /// 生成年度生产大纲
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<string> SaveAnnualProductionOutline(InputDto input);
+
+        /// <summary>
+        /// 刷新年度销售预测
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<string> DemandAnalysis(InputDto input);
+
+        /// <summary>
+        /// 定时任务长周期物料
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        Task<string> CalcLongPeriodItemPR(InputDto input);
+
+        /// <summary>
+        /// 生成整体需求计划
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        //Task<string> OverallDemandPlan(InputDto input);
+
+
         /// <summary>
         /// 调整ROP和最高库存水位
         /// </summary>
         Task<string> CalcROP(InputDto input);
 
+        /// <summary>
+        /// 根据月计划生产周计划
+        /// </summary>
+        /// <param name="companyId">工厂id</param>
+        /// <returns></returns>
+        Task<string> CalcWeekPlan(InputDto input);
+
+        /// <summary>
+        /// 根据月计划生产周计划
+        /// </summary>
+        /// <param name="companyId">工厂id</param>
+        /// <returns></returns>
+        Task<string> CalcDayPlan(InputDto input);
+
         /// <summary>
         /// 检查所有成品半成品原材料是否需要补货先判断SS再判断ROP
         /// </summary>
         /// <param name="input"></param>
         /// <returns></returns>
         Task<string> DayCheckAllByFinalGoods(InputDto input);
-
-        Task<string> LongPeriodItemPR(InputDto input, int month);
     }
 }

+ 0 - 20
MicroServices/Business/Business.Application.Contracts/SaleForecast/IAnnualProductionOutlineAppService.cs

@@ -1,20 +0,0 @@
-using Business.Dto;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Volo.Abp.Application.Services;
-
-namespace Business.SaleForecast
-{
-    public interface IAnnualProductionOutlineAppService : IApplicationService
-    {
-        /// <summary>
-        /// 生成年度生产大纲
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        Task<string> SaveAnnualProductionOutline(InputDto input);
-    }
-}

+ 0 - 38
MicroServices/Business/Business.Application.Contracts/SaleForecast/IMonthlyCapacityLoadAppService.cs

@@ -1,38 +0,0 @@
-using Business.Dto;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Volo.Abp.Application.Services;
-
-namespace Business.SaleForecast
-{
-    /// <summary>
-    /// 产能分析接口
-    /// </summary>
-    public interface IMonthlyCapacityLoadAppService: IApplicationService
-    {
-        ///// <summary>
-        ///// 产能分析
-        ///// </summary>
-        ///// <param name="input"></param>
-        ///// <returns></returns>
-        //Task<string> CapacityAnalysis(InputDto input);
-
-        /// <summary>
-        /// 月度需求分析
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        Task<string> DemandAnalysis(InputDto input);
-
-        /// <summary>
-        /// 生成整体需求计划
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        Task<string> OverallDemandPlan(InputDto input);
-    }
-}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 901 - 32
MicroServices/Business/Business.Application/ReplenishmentManagement/ReplenishmentAppService.cs


+ 20 - 2
MicroServices/Business/Business.Application/ResourceExamineManagement/CalcBomViewAppService.cs

@@ -35,6 +35,7 @@ namespace Business.ResourceExamineManagement
         public List<mo_ic_item> ic_item_List = new List<mo_ic_item>();
         public List<mo_srm_po_list> srm_Po_Lists = new List<mo_srm_po_list>();
         public List<mo_srm_po_occupy> srm_Po_Occupies = new List<mo_srm_po_occupy>();
+        public List<mo_srm_pr_main> srm_Pr_Mains = new List<mo_srm_pr_main>();
         public List<mo_srm_po_occupy> srm_Po_OccupiesInsert = new List<mo_srm_po_occupy>();
 
         public List<mo_ic_item_stockoccupy> newStockOccList = new List<mo_ic_item_stockoccupy>();
@@ -299,8 +300,13 @@ namespace Business.ResourceExamineManagement
                             CalcInTransit(sentrys, level1Dto, bangid, plan_date.GetValueOrDefault());
                             if (level1Dto.lack_qty > 0)
                             {
-                                //采购申请
-                                PackageSRMPR(level1Dto, bangid, sentrys, plan_date);
+                                decimal itemPRQty = srm_Pr_Mains.Where(x => x.icitem_id.Value == level1Dto.item_id && x.pr_parrive_date <= plan_date).Sum(y => y.pr_aqty.GetValueOrDefault());
+                                if (itemPRQty < level1Dto.lack_qty)
+                                {
+                                    level1Dto.lack_qty = level1Dto.lack_qty - itemPRQty;
+                                    //采购申请
+                                    PackageSRMPR(level1Dto, bangid, sentrys, plan_date);
+                                }
                             }
                         }
                         else if (level1Dto.erp_cls == 2)
@@ -322,6 +328,18 @@ namespace Business.ResourceExamineManagement
                                     MatterTileDevelop(level1Dto, childList, returnlist, sklist, bangid, plan_date, sentrys, icitemlist);
                                     level1Dto.kitting_time = childList.Max(s => s.kitting_time).GetValueOrDefault().AddDays(srmprDto.totalLeadTime.GetValueOrDefault());//加上物料的采购提前期
                                 }
+
+                                //2.生成采购申请
+                                //采购申请
+                                decimal itemPRQty = srm_Pr_Mains.Where(x => x.icitem_id.Value == level1Dto.item_id && x.pr_parrive_date <= plan_date).Sum(y => y.pr_aqty.GetValueOrDefault());
+                                if (itemPRQty < level1Dto.lack_qty)
+                                {
+                                    level1Dto.lack_qty = level1Dto.lack_qty - itemPRQty;
+                                    //采购申请
+                                    PackageSRMPR(level1Dto, bangid, sentrys, plan_date);
+                                }
+                                //PackageSRMPR(level1Dto, bangid, sentrys);
+
                                 level1Dto.subcontracting_qty = level1Dto.lack_qty;
                                 level1Dto.subcontracting_list = new List<ooder>();
                                 ooder oo = new ooder();

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

@@ -218,6 +218,7 @@ namespace Business.ResourceExamineManagement
             mes_Moentry.morder_production_number = generateMorderDto.Quantity;
             mes_Moentry.need_number = generateMorderDto.Quantity;
             mes_Moentry.remaining_number = 0;
+            mes_Moentry.tenant_id = param.company_id.GetValueOrDefault();
             mes_Moentry.factory_id = param.factoryId;
             mes_Moentry.company_id = param.company_id;
             mes_Moentry.org_id = param.org_id;

+ 73 - 70
MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs

@@ -709,10 +709,9 @@ namespace Business.ResourceExamineManagement
                                 //剩余可用工作时长不能满足清场时长
                                 else
                                 {
-                                    endTime = dto.EndTime;
                                     //还需排产的清场时间
                                     decimal qcTime = needTime - remainTime;
-                                    endTime.AddMinutes((double)qcTime);
+                                    endTime = dto.EndTime.AddMinutes((double)qcTime);
                                     remainTime = 0;
                                 }
                                 //最后一个工单的清场时长
@@ -797,7 +796,7 @@ namespace Business.ResourceExamineManagement
                             item.QtyWorked = item.QtyOrded;
                         }
                         //当天产能完全占用,且最后一个工单的清场时间刚好下班或者在下班后
-                        if (curPoint == null || endTime == dto.EndTime)
+                        if (endTime >= dto.EndTime)
                         {
                             sumTsTimes = 0;//排产完毕,特殊工单时长置0
                             //获取下一个工作日
@@ -965,17 +964,17 @@ namespace Business.ResourceExamineManagement
                                 });
                                 //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
                                 item.Worked = item.LbrVar;
-                                item.QtyWorked = item.QtyWorked;
+                                item.QtyWorked = item.QtyOrded;
 
                                 beginTime = endTime;
                                 //当天可用生产时长还有剩余
                                 if (residueTime > 0)
                                 {
                                     //获取结束时间所处时间段
-                                    curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
+                                    curPoint = workPoints.FirstOrDefault(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
                                     if (endTime == curPoint.EndPoint)
                                     {
-                                        var nextPoint = workPoints.Find(p => p.Level == curPoint.Level + 1);
+                                        var nextPoint = workPoints.FirstOrDefault(p => p.Level == curPoint.Level + 1);
                                         endTime = nextPoint == null ? endTime : nextPoint.StartPoint;
                                     }
                                     beginTime = endTime;
@@ -1067,29 +1066,32 @@ namespace Business.ResourceExamineManagement
                     {
                         //获取特殊工单
                         secWOMasters = tsWorkOrds.Where(p => p.ProdLine == lineStart.Line && p.OrdDate.Value.Date == workStartTime.Date).OrderBy(p => p.OrdDate).ToList();
-                        foreach (var item in secWOMasters)
+                        if (secWOMasters.Any())
                         {
-                            var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
-                            workDtos.Add(new WorkOrdMstDto
+                            foreach (var item in secWOMasters)
                             {
-                                WorkOrd = item.WorkOrd,
-                                ItemNum = item.ItemNum,
-                                QtyOrded = item.QtyOrded,
-                                LbrVar = item.LbrVar * 60,
-                                Worked = 0,
-                                QtyWorked = 0,
-                                Op = curOp.OP,
-                                WaitTime = curOp.WaitTime * 60,
-                                PlanDate = item.OrdDate.Value
-                            });
-                            sumCleanTimes += curOp.WaitTime * 60;
+                                var curOp = tsWoRoutings.Where(p => p.WorkOrd == item.WorkOrd).OrderByDescending(p => p.OP).First();
+                                workDtos.Add(new WorkOrdMstDto
+                                {
+                                    WorkOrd = item.WorkOrd,
+                                    ItemNum = item.ItemNum,
+                                    QtyOrded = item.QtyOrded,
+                                    LbrVar = item.LbrVar * 60,
+                                    Worked = 0,
+                                    QtyWorked = 0,
+                                    Op = curOp.OP,
+                                    WaitTime = curOp.WaitTime * 60,
+                                    PlanDate = item.OrdDate.Value
+                                });
+                                sumCleanTimes += curOp.WaitTime * 60;
+                            }
+                            //获取最后一个特殊工单的清场时长
+                            var last = secWOMasters.Last();
+                            secCleanTime = tsWoRoutings.Where(p => p.WorkOrd == last.WorkOrd).OrderByDescending(p => p.OP).First().WaitTime * 60;
+                            //特殊工单待排产时长=前一天特殊工单到最后一个清场时长+新增的特殊工单生产时长+新增特殊工单除最后一个清场时长之外的清场时长之和
+                            sumTsTimes += (lstCleanTime + secWOMasters.Sum(p => p.LbrVar) * 60 + sumCleanTimes - secCleanTime);
+                            lstCleanTime = secCleanTime;
                         }
-                        //获取最后一个特殊工单的清场时长
-                        var last = secWOMasters.Last();
-                        secCleanTime = tsWoRoutings.Where(p => p.WorkOrd == last.WorkOrd).OrderByDescending(p => p.OP).First().WaitTime * 60;
-                        //特殊工单待排产时长=前一天特殊工单到最后一个清场时长+新增的特殊工单生产时长+新增特殊工单除最后一个清场时长之外的清场时长之和
-                        sumTsTimes += (lstCleanTime + secWOMasters.Sum(p => p.LbrVar) * 60 + sumCleanTimes - secCleanTime);
-                        lstCleanTime = secCleanTime;
                     }
                     //排产开始时,需要先减去产线准备时间(产线提前期满足的当天排产)
                     if (sumTimes < lineStart.setupTime * 60)
@@ -1097,7 +1099,7 @@ namespace Business.ResourceExamineManagement
                         //当天的可用生产时长能满足提前期
                         if (dto.EffTime > lineStart.setupTime * 60 - sumTimes)
                         {
-                            //当天剩余时长(分钟)
+                            //当天剩余时长(分钟)=当天可用上产时长-剩余产线准备时间
                             decimal residueTime = dto.EffTime - (lineStart.setupTime * 60 - sumTimes);
                             //产线提前期安排完之后,需要考虑当前是否存在特殊工单:
                             //1、如果当天是排产的最后一天,则先排完正常工单,再安排特殊工单;
@@ -1164,10 +1166,9 @@ namespace Business.ResourceExamineManagement
                                                 //剩余可用工作时长不能满足清场时长
                                                 else
                                                 {
-                                                    endTime = dto.EndTime;
                                                     //还需排产的清场时间
                                                     decimal qcTime = needTime - residueTime;
-                                                    endTime.AddMinutes((double)qcTime);
+                                                    endTime = dto.EndTime.AddMinutes((double)qcTime);
                                                     residueTime = 0;
                                                 }
                                             }
@@ -1259,7 +1260,7 @@ namespace Business.ResourceExamineManagement
                                             //处理正常工单开工时间
                                             workStartTime = endTime;
                                             //剩余产能继续排正常工单
-                                            sumAmount = Math.Floor(dto.Rate * (residueTime - sumTsTimes - lstCleanTime) / 60);
+                                            sumAmount = Math.Floor(dto.Rate * residueTime / 60);
                                             //记录生产周期
                                             curSequences.Add(new PeriodSequenceDet
                                             {
@@ -1387,10 +1388,6 @@ namespace Business.ResourceExamineManagement
                                                     //剩余生产时长
                                                     residueTime -= needTime;
                                                 }
-                                                //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
-                                                item.Worked = item.LbrVar;
-                                                item.QtyWorked = item.QtyWorked;
-
                                                 //处理特殊工单剩余时长减去当前工单待排产时长和清场时长
                                                 sumTsTimes -= (item.LbrVar - item.Worked + item.WaitTime);
                                                 //记录生产周期
@@ -1422,6 +1419,9 @@ namespace Business.ResourceExamineManagement
                                                     WorkEndTime = endTime,
                                                     CreateTime = DateTime.Now
                                                 });
+                                                //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
+                                                item.Worked = item.LbrVar;
+                                                item.QtyWorked = item.QtyOrded;
 
                                                 beginTime = endTime;
                                                 //当天可用生产时长还有剩余
@@ -1471,7 +1471,7 @@ namespace Business.ResourceExamineManagement
                                                     WorkDate = beginTime.Date,
                                                     WorkQty = qty,
                                                     WorkStartTime = beginTime,
-                                                    WorkEndTime = endTime,
+                                                    WorkEndTime = dto.EndTime,
                                                     CreateTime = DateTime.Now
                                                 });
                                                 item.Worked += residueTime;
@@ -1536,11 +1536,14 @@ namespace Business.ResourceExamineManagement
                                 decimal residueQty = workOrd.QtyOrded - sumQty;
                                 //剩余数量生产需要时长(分钟)
                                 decimal workTime = Math.Ceiling(residueQty / dto.Rate * 60);
+                                //处理工作时长:防止相上取整导致时间大于剩余可用时长
+                                workTime = workTime >= residueTime ? residueTime : workTime;
+                                //排产结束时间
+                                DateTime workEndTime = workStartTime;
                                 var curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
                                 span = curPoint.EndPoint - workStartTime;
                                 //当天工作时间段的有效生产时间
                                 decimal effMins = (decimal)span.TotalMinutes;
-                                DateTime workEndTime = workStartTime;
                                 //当前工作时间段即可满足产能
                                 if (effMins >= workTime)
                                 {
@@ -1608,7 +1611,7 @@ namespace Business.ResourceExamineManagement
                                     }
                                     residueTime -= workTime;
                                 }
-
+                                
                                 //记录生产周期
                                 curSequences.Add(new PeriodSequenceDet
                                 {
@@ -1708,10 +1711,9 @@ namespace Business.ResourceExamineManagement
                                                     //剩余可用工作时长不能满足清场时长
                                                     else
                                                     {
-                                                        endTime = dto.EndTime;
                                                         //还需排产的清场时间
                                                         decimal qcTime = needTime - restTime;
-                                                        endTime.AddMinutes((double)qcTime);
+                                                        endTime = dto.EndTime.AddMinutes((double)qcTime);
                                                         restTime = 0;
                                                     }
                                                     //最后一个工单的清场时长
@@ -1917,10 +1919,9 @@ namespace Business.ResourceExamineManagement
                                                     });
                                                     //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
                                                     item.Worked = item.LbrVar;
-                                                    item.QtyWorked = item.QtyWorked;
+                                                    item.QtyWorked = item.QtyOrded;
 
                                                     beginTime = endTime;
-                                                    curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
                                                     if (restTime > 0)
                                                     {
                                                         curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
@@ -1931,6 +1932,7 @@ namespace Business.ResourceExamineManagement
                                                             {
                                                                 endTime = nextPoint.StartPoint;
                                                             }
+                                                            beginTime = endTime;
                                                         }
                                                     }
                                                     //当天产能已全部用完
@@ -1970,14 +1972,14 @@ namespace Business.ResourceExamineManagement
                                                         WorkDate = beginTime.Date,
                                                         WorkQty = qty,
                                                         WorkStartTime = beginTime,
-                                                        WorkEndTime = endTime,
+                                                        WorkEndTime = dto.EndTime,
                                                         CreateTime = DateTime.Now
                                                     });
                                                     item.Worked += restTime;
                                                     item.QtyWorked += qty;
-                                                    restTime = 0m;
                                                     //特殊工单剩余待排产时长(分钟)
                                                     sumTsTimes -= restTime;
+                                                    restTime = 0m;
                                                     break;
                                                 }
                                             }
@@ -2044,7 +2046,7 @@ namespace Business.ResourceExamineManagement
                                     if (item.WorkOrd == lastWork.WorkOrd)
                                     {
                                         //最后一个工单的生产时长+清场时长
-                                        needTime = lastWork.QtyOrded - lastWork.QtyWorked + lastWork.WaitTime;
+                                        needTime = lastWork.LbrVar - lastWork.Worked + lastWork.WaitTime;
                                         //剩余可用工作时长满足最后一个特殊工单的生产时长+清场时长
                                         if (residueTime >= needTime)
                                         {
@@ -2072,10 +2074,9 @@ namespace Business.ResourceExamineManagement
                                         //剩余可用工作时长不能满足清场时长
                                         else
                                         {
-                                            endTime = dto.EndTime;
                                             //还需排产的清场时间
                                             decimal qcTime = needTime - residueTime;
-                                            endTime.AddMinutes((double)qcTime);
+                                            endTime = dto.EndTime.AddMinutes((double)qcTime);
                                             residueTime = 0;
                                         }
                                         //最后一个工单的清场时长
@@ -2165,12 +2166,19 @@ namespace Business.ResourceExamineManagement
                                     item.Worked = item.LbrVar;
                                     item.QtyWorked = item.QtyOrded;
                                 }
+                                //排产完毕,特殊工单时长置0
+                                sumTsTimes = 0;
+                                //当天特殊工单全部排产完成
+                                isFullPC = true;
+                                //特殊工单排产完成,最后一个工单的清场时长置0
+                                lstCleanTime = 0m;
 
                                 //剩余可用生产时长
                                 residueTime = residueTime < 0 ? 0 : residueTime;
                                 //特殊工单处理完成,剩余生产时长大于0且还有正常工单待排产,则继续排正常工单
                                 if (residueTime > 0 && sumQty < workOrd.QtyOrded)
                                 {
+                                    workStartTime = beginTime;//排产开始时间
                                     //剩余产能继续排正常工单
                                     decimal sumAmount = Math.Floor(dto.Rate * residueTime / 60);
                                     //如果剩余产能不能满足正常工单,剩余产能全部排产
@@ -2214,20 +2222,20 @@ namespace Business.ResourceExamineManagement
                                     //剩余产能满足正常工单待排产数量,此时需要排清场时长
                                     else
                                     {
-                                        workStartTime = beginTime;
                                         //剩余需要排产的数量
                                         decimal residueQty = workOrd.QtyOrded - sumQty;
                                         //剩余数量生产需要时长(分钟)
                                         decimal workTime = Math.Ceiling(residueQty / dto.Rate * 60);
+                                        //处理剩余需要生产时长:防止向上取整导致超过residueTime
+                                        workTime = workTime > residueTime ? residueTime : workTime;
                                         curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
                                         span = curPoint.EndPoint - workStartTime;
                                         //当天工作时间段的有效生产时间
                                         decimal effMins = (decimal)span.TotalMinutes;
-                                        DateTime workEndTime = workStartTime;
                                         //当前工作时间段即可满足产能
                                         if (effMins >= workTime)
                                         {
-                                            workEndTime = workStartTime.AddMinutes((double)workTime);
+                                            endTime = workStartTime.AddMinutes((double)workTime);
                                         }
                                         else
                                         {
@@ -2239,7 +2247,7 @@ namespace Business.ResourceExamineManagement
                                             {
                                                 if (p.WorkMinutes >= nextMins)
                                                 {
-                                                    workEndTime = p.StartPoint.AddMinutes((double)nextMins);
+                                                    endTime = p.StartPoint.AddMinutes((double)nextMins);
                                                     break;
                                                 }
                                                 nextMins -= p.WorkMinutes;
@@ -2319,7 +2327,7 @@ namespace Business.ResourceExamineManagement
                                             WorkDate = workStartTime.Date,
                                             WorkQty = residueQty,
                                             WorkStartTime = workStartTime,
-                                            WorkEndTime = workEndTime,
+                                            WorkEndTime = endTime,
                                             CreateTime = DateTime.Now
                                         });
                                     }
@@ -2329,12 +2337,6 @@ namespace Business.ResourceExamineManagement
                                     workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
                                     isFstDay = false;
                                 }
-                                //排产完毕,特殊工单时长置0
-                                sumTsTimes = 0;
-                                //当天特殊工单全部排产完成
-                                isFullPC = true;
-                                //特殊工单排产完成,最后一个工单的清场时长置0
-                                lstCleanTime = 0m;
                             }
                             //当天的可用产能不满特殊工单生产时长,则当天产能全部排特殊工单(至少最后一个特殊工单的生产时长不能满足)
                             else
@@ -2456,7 +2458,7 @@ namespace Business.ResourceExamineManagement
                                         });
                                         //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
                                         item.Worked = item.LbrVar;
-                                        item.QtyWorked = item.QtyWorked;
+                                        item.QtyWorked = item.QtyOrded;
 
                                         beginTime = endTime;
                                         //当天可用生产时长还有剩余
@@ -2466,7 +2468,7 @@ namespace Business.ResourceExamineManagement
                                             curPoint = workPoints.Find(p => p.StartPoint <= endTime && endTime <= p.EndPoint);
                                             if (endTime == curPoint.EndPoint)
                                             {
-                                                var nextPoint = workPoints.Find(p => p.Level == curPoint.Level + 1);
+                                                var nextPoint = workPoints.FirstOrDefault(p => p.Level == curPoint.Level + 1);
                                                 endTime = nextPoint == null ? endTime : nextPoint.StartPoint;
                                             }
                                             beginTime = endTime;
@@ -2508,7 +2510,7 @@ namespace Business.ResourceExamineManagement
                                             WorkDate = beginTime.Date,
                                             WorkQty = qty,
                                             WorkStartTime = beginTime,
-                                            WorkEndTime = endTime,
+                                            WorkEndTime = dto.EndTime,
                                             CreateTime = DateTime.Now
                                         });
                                         item.Worked += residueTime;
@@ -2558,7 +2560,7 @@ namespace Business.ResourceExamineManagement
                                             if (item.WorkOrd == lastWork.WorkOrd) 
                                             {
                                                 //最后一个工单的生产时长+清场时长
-                                                needTime = lastWork.QtyOrded - lastWork.QtyWorked + lastWork.WaitTime;
+                                                needTime = lastWork.LbrVar - lastWork.Worked + lastWork.WaitTime;
                                                 //剩余可用工作时长满足最后一个特殊工单的生产时长+清场时长
                                                 if (residueTime >= needTime)
                                                 {
@@ -2586,10 +2588,9 @@ namespace Business.ResourceExamineManagement
                                                 //剩余可用工作时长不能满足清场时长
                                                 else
                                                 {
-                                                    endTime = dto.EndTime;
                                                     //还需排产的清场时间
                                                     decimal qcTime = needTime - residueTime;
-                                                    endTime.AddMinutes((double)qcTime);
+                                                    endTime = dto.EndTime.AddMinutes((double)qcTime);
                                                     residueTime = 0;
                                                 }
                                                 //最后一个工单的清场时长
@@ -2845,7 +2846,7 @@ namespace Business.ResourceExamineManagement
                                                 });
                                                 //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
                                                 item.Worked = item.LbrVar;
-                                                item.QtyWorked = item.QtyWorked;
+                                                item.QtyWorked = item.QtyOrded;
 
                                                 beginTime = endTime;
                                                 if (residueTime > 0)
@@ -2896,7 +2897,7 @@ namespace Business.ResourceExamineManagement
                                                     WorkDate = beginTime.Date,
                                                     WorkQty = qty,
                                                     WorkStartTime = beginTime,
-                                                    WorkEndTime = endTime,
+                                                    WorkEndTime = dto.EndTime,
                                                     CreateTime = DateTime.Now
                                                 });
                                                 item.Worked += residueTime;
@@ -2951,6 +2952,7 @@ namespace Business.ResourceExamineManagement
                                     //继续排下一个工作日
                                     workStartTime = GetNextWorkDay((int)workStartTime.DayOfWeek, workStartTime, mLCalendars);
                                     isFstDay = false;
+                                    isFullPC = true;
                                 }
                             }
                             //剩余产能满足正常工单待排产数量,此时需要排清场时长
@@ -2968,6 +2970,8 @@ namespace Business.ResourceExamineManagement
                                     decimal residueQty = workOrd.QtyOrded - sumQty;
                                     //剩余数量生产需要时长(分钟)
                                     workTime = Math.Ceiling(residueQty / dto.Rate * 60);
+                                    //处理需要生产时长
+                                    workTime = workTime >= residueTime ? residueTime : workTime;
                                     var curPoint = workPoints.Find(p => p.StartPoint <= workStartTime && workStartTime <= p.EndPoint);
                                     span = curPoint.EndPoint - workStartTime;
                                     //当天工作时间段的有效生产时间
@@ -3110,7 +3114,7 @@ namespace Business.ResourceExamineManagement
                                                 if (item.WorkOrd == lastWork.WorkOrd)
                                                 {
                                                     //最后一个工单的生产时长+清场时长
-                                                    needTime = lastWork.QtyOrded - lastWork.QtyWorked + lastWork.WaitTime;
+                                                    needTime = lastWork.LbrVar - lastWork.Worked + lastWork.WaitTime;
                                                     //剩余可用工作时长满足最后一个特殊工单的生产时长+清场时长
                                                     if (residueTime >= needTime)
                                                     {
@@ -3139,10 +3143,9 @@ namespace Business.ResourceExamineManagement
                                                     //剩余可用工作时长不能满足清场时长
                                                     else
                                                     {
-                                                        endTime = dto.EndTime;
                                                         //还需排产的清场时间
                                                         decimal qcTime = needTime - residueTime;
-                                                        endTime.AddMinutes((double)qcTime);
+                                                        endTime = dto.EndTime.AddMinutes((double)qcTime);
                                                         residueTime = 0;
                                                     }
                                                     //最后一个工单的清场时长
@@ -3352,7 +3355,7 @@ namespace Business.ResourceExamineManagement
                                                     });
                                                     //当前工单已排产完成,已排产时间=工单生产时长,已排产数量=工单数量
                                                     item.Worked = item.LbrVar;
-                                                    item.QtyWorked = item.QtyWorked;
+                                                    item.QtyWorked = item.QtyOrded;
 
                                                     beginTime = endTime;
                                                     if (residueTime > 0)
@@ -3402,7 +3405,7 @@ namespace Business.ResourceExamineManagement
                                                         WorkDate = beginTime.Date,
                                                         WorkQty = qty,
                                                         WorkStartTime = beginTime,
-                                                        WorkEndTime = endTime,
+                                                        WorkEndTime = dto.EndTime,
                                                         CreateTime = DateTime.Now
                                                     });
                                                     item.Worked += residueTime;

+ 16 - 1
MicroServices/Business/Business.Application/ResourceExamineManagement/ResourceExamineAppService.cs

@@ -459,7 +459,7 @@ namespace Business.ResourceExamineManagement
             IRepository<ic_substitute, long> mysql_ic_substitute,
             IRepository<ic_substitute_group, long> mysql_ic_substitute_group,
             IRepository<ic_substitute_group_detail, long> mysql_ic_substitute_group_detail,
-            IRepository<ReplenishmentModel, long> replenishmentModel,
+            IRepository<ReplenishmentROP, long> replenishmentROP,
             IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
             ISqlRepository<ASNBOLShipperDetail> ASNBOLShipperDetail,
             IRepository<StandardItemModelSet, long> standardItemModelSet,
@@ -1880,6 +1880,15 @@ namespace Business.ResourceExamineManagement
                 moSrm_po_occupy.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; });
                 await _srm_po_occupy.InsertManyAsync(moSrm_po_occupy);
             }
+
+            //pr
+            var srm_pr_main = _mysql_srm_pr_main.GetListAsync(x => x.company_id == companyId && x.factory_id == factoryId && itemIds.Contains(x.icitem_id.GetValueOrDefault())).Result;
+            if(srm_pr_main.Count>0)
+            {
+                var moSrm_pr_main = ObjectMapper.Map<List<srm_pr_main>, List<mo_srm_pr_main>>(srm_pr_main);
+                moSrm_pr_main.ForEach(item => { item.GenerateNewId(help.NextId()); item.bang_id = bangid; });
+                await _srm_pr_main.InsertManyAsync(moSrm_pr_main);
+            }
         }
 
         /// <summary>
@@ -1908,6 +1917,9 @@ namespace Business.ResourceExamineManagement
 
             //清除采购订单占用详情
             //await _srm_po_occupy.DeleteAsync(p => p.bang_id == bangid);
+
+            //清除PR
+            await _srm_pr_main.DeleteAsync(p => p.bang_id == bangid);
         }
 
         /// <summary>
@@ -3201,6 +3213,8 @@ namespace Business.ResourceExamineManagement
             var poDetailList = _srm_po_list.GetListAsync(x => icitemlist.Select(p => p.mysql_id).ToList().Contains(x.icitem_id.Value) && x.bang_id == bangid && x.state == 1 && x.rstate == 1 && !x.IsDeleted).Result;
             //采购订单占用数据
             var poOccupys = _srm_po_occupy.GetListAsync(x => poDetailList.Select(p => p.Id).ToList().Contains(x.polist_id) && x.bang_id == bangid && !x.IsDeleted).Result;
+
+            var srm_pr_mains = _srm_pr_main.GetListAsync(x => icitemlist.Select(p => p.mysql_id).ToList().Contains(x.icitem_id.Value) && x.bang_id == bangid && x.state == 0 && !x.IsDeleted).Result;
             #endregion
 
             //处理一下已经插入得占用记录
@@ -3231,6 +3245,7 @@ namespace Business.ResourceExamineManagement
             _CalcBomViewAppService.srm_Po_Lists = poDetailList; //采购明细
             _CalcBomViewAppService.srm_Po_Occupies = poOccupys; //采购占用表
             _CalcBomViewAppService.ic_item_List = icitemlist; //物料表
+            _CalcBomViewAppService.srm_Pr_Mains = srm_pr_mains;//PR
         }
 
         public void GenerateSort(List<BomChildExamineDto> returnlist)

+ 0 - 308
MicroServices/Business/Business.Application/SaleForecastManagement/AnnualProductionOutlineAppService.cs

@@ -1,308 +0,0 @@
-using Business.Core.Enum;
-using Business.Core.Utilities;
-using Business.Domain;
-using Business.Dto;
-using Business.EntityFrameworkCore.SqlRepositories;
-using Business.SaleForecast;
-using Business.StructuredDB.SaleFcst;
-using Business.StructuredDB.WMS;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using NetTopologySuite.Algorithm;
-using RazorEngine;
-using Spire.Pdf.General.Render.Decode.Jpeg2000.j2k.wavelet.synthesis;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Volo.Abp.Application.Dtos;
-using Volo.Abp.Application.Services;
-using Volo.Abp.DependencyInjection;
-using Volo.Abp.Domain.Repositories;
-using Volo.Abp.MultiTenancy;
-using Volo.Abp.Uow;
-using ZstdSharp.Unsafe;
-using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
-
-namespace Business.SaleForecastManagement
-{
-    public class AnnualProductionOutlineAppService : ApplicationService, ITransientDependency, IAnnualProductionOutlineAppService
-    {
-        #region 服务
-        /// <summary>
-        /// 工作单元
-        /// </summary>
-        private readonly IUnitOfWorkManager _unitOfWorkManager;
-
-        /// <summary>
-        /// 日志
-        /// </summary>
-        private readonly ICurrentTenant _currentTenant;
-
-        /// <summary>
-        /// 年度销售预测
-        /// </summary>
-        private IRepository<YearDemandManagement, long> _yearDemandManagement;
-
-        /// <summary>
-        /// 年度销售预测历史记录
-        /// </summary>
-        private IRepository<YearDemandManagementHistory, long> _yearDemandManagementHistory;
-
-        /// <summary>
-        /// 年度生产大纲
-        /// </summary>
-        private IRepository<AnnualProductionOutline, long> _annualProductionOutline;
-
-        /// <summary>
-        /// 生产线明细
-        /// </summary>
-        private ISqlRepository<ProdLineDetail> _prodLineDetail;
-
-        /// <summary>
-        /// 标准工艺流程表
-        /// </summary>
-        private ISqlRepository<RoutingOpDetail> _routingOpDetail;
-        /// <summary>
-        /// 库存表
-        /// </summary>
-        private ISqlRepository<LocationDetail> _locationDetail;
-        /// <summary>
-        /// 平台库存表
-        /// </summary>
-        private readonly IRepository<WMS_PlatformInventory, long> _PlatformInventory;
-        /// <summary>
-        /// 已发货记录
-        /// </summary>
-        private ISqlRepository<ASNBOLShipperDetail> _ASNBOLShipperDetail;
-        /// <summary>
-        /// 工单工艺路线明细
-        /// </summary>
-        private ISqlRepository<WorkOrdRouting> _workOrdRouting;
-        /// <summary>
-        /// 补货模型
-        /// </summary>
-        private IRepository<ReplenishmentModel, long> _replenishmentModel;
-        /// <summary>
-        /// 主生产计划
-        /// </summary>
-        private IRepository<ProductionMasterPlan, long> _productionMasterPlan;
-
-
-        /// <summary>
-        /// 雪花算法
-        /// </summary>
-        SnowFlake help = new SnowFlake();
-        #endregion
-
-        #region 构造函数
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        public AnnualProductionOutlineAppService(
-
-            IUnitOfWorkManager unitOfWorkManager,
-            ICurrentTenant currentTenant,
-            IRepository<YearDemandManagement, long> yearDemandManagement,
-            IRepository<AnnualProductionOutline, long> annualProductionOutline,
-            IRepository<YearDemandManagementHistory, long> yearDemandManagementHistory,
-            ISqlRepository<ProdLineDetail> prodLineDetail,
-            IRepository<WMS_PlatformInventory, long> PlatformInventory,
-            ISqlRepository<RoutingOpDetail> routingOpDetail,
-            ISqlRepository<ASNBOLShipperDetail> ASNBOLShipperDetail,
-            ISqlRepository<WorkOrdRouting> workOrdRouting,
-            ISqlRepository<LocationDetail> locationDetail,
-            IRepository<ReplenishmentModel, long> replenishmentModel,
-            IRepository<ProductionMasterPlan, long> productionMasterPlan
-            )
-        {
-            _unitOfWorkManager = unitOfWorkManager;
-            _currentTenant = currentTenant;
-            _PlatformInventory = PlatformInventory;
-            _prodLineDetail = prodLineDetail;
-            _workOrdRouting = workOrdRouting;
-            _routingOpDetail = routingOpDetail;
-            _locationDetail = locationDetail;
-            _ASNBOLShipperDetail = ASNBOLShipperDetail;
-            _yearDemandManagement = yearDemandManagement;
-            _yearDemandManagementHistory = yearDemandManagementHistory;
-            _annualProductionOutline = annualProductionOutline;
-            _replenishmentModel = replenishmentModel;
-            _productionMasterPlan = productionMasterPlan;
-        }
-        #endregion
-        /// <summary>
-        /// 生成年度生产大纲
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        /// <exception cref="NotImplementedException"></exception>
-        public async Task<string> SaveAnnualProductionOutline(InputDto input)
-        {
-            //获取当前导入或修改数据
-            List<YearDemandManagement> yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ThenBy(o => o.PlanMonth).ToList();
-            //标准工艺路径表
-            List<RoutingOpDetail> routingOps = _routingOpDetail.Select(p => yearDemands.Select(m => m.SAPItemNumber).Contains(p.RoutingCode) && p.Domain == input.factory_id.ToString() && p.IsActive);
-            var routingOpList = routingOps.Where(x => x.Descr == "组装").ToList();
-            //生产线明细表
-            List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => yearDemands.Select(m => m.SAPItemNumber).Contains(p.Part) && p.Domain == input.factory_id.ToString() && p.IsActive && routingOpList.Select(m => m.Op).Contains(p.Op)).OrderBy(x => x.Sequence).ToList();
-            List<LocationDetail> locations = _locationDetail.Select(x => yearDemands.Select(m => m.SAPItemNumber).Contains(x.ItemNum) && x.Domain == input.factory_id.ToString() && x.IsActive).ToList();
-            //平台库存
-            var platformInvList = _PlatformInventory.GetListAsync(a => yearDemands.Select(m => m.SAPItemNumber).Contains(a.SAPItemNumber) && a.tenant_id == input.tenant_id && a.factory_id == input.factory_id && !a.IsDeleted).Result;
-            var replenishmentModels = _replenishmentModel.GetListAsync(x => !x.IsDeleted && x.isparam && yearDemands.Select(m => m.SAPItemNumber).Contains(x.number)).Result.ToList();
-            // 获取某年某月的起始日期和结束日期
-            int year = input.year;
-            int month = DateTime.Now.Month;
-            DateTime start = new DateTime(year, month, 1);
-            DateTime end = start.AddMonths(1).AddDays(-1);
-            //取当月发货出库记录
-            var shipList = _ASNBOLShipperDetail.Select(a => a.Domain == input.factory_id.ToString() && a.IsActive && a.shtype == "SH" && a.Typed != "S" && a.RealQty > 0 && yearDemands.Select(p => p.SAPItemNumber).Contains(a.ContainerItem)).Where(s => s.ShipDate >= start && s.ShipDate <= end);
-            #region 在制数量
-            //获取在制数量 获取工单数取每年4月到12月底的工单
-            DateTime startYear = new DateTime(year, 4, 1);
-            DateTime endYear = new DateTime(year, 12, 31);
-            List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(x => x.IsActive && x.QtyComplete > 0 && x.Domain == input.factory_id.ToString()).Where(p => p.DueDate >= startYear && p.DueDate <= endYear).ToList();
-            decimal? InProductionQty = 0.00m;
-            var workOrds = workOrdRoutings.GroupBy(x => x.WorkOrd).ToList();
-            //按照工单循环
-            //某工单10-90工序   Max(10-80工序QtyComplete)-90工序QtyComplete =在制数量
-            foreach (var item in workOrds)
-            {
-                var workOrdRoutingList = workOrdRoutings.Where(x => x.WorkOrd == item.Key).OrderByDescending(o => o.OP).ToList();
-                //找出最大工序
-                var MaxOp = workOrdRoutingList.FirstOrDefault();
-                //查询出其他工序最大值
-                var MaxQtyComplete = workOrdRoutingList.Where(x => x.RecID != MaxOp.RecID).ToList().Max(o => o.QtyComplete);
-                InProductionQty += MaxQtyComplete - MaxOp.QtyComplete;
-            }
-            #endregion
-            //年度生产大纲实体
-            List<AnnualProductionOutline> annualProductionOutlines = new List<AnnualProductionOutline>();
-            List<YearDemandManagement> frontYearDemand = new List<YearDemandManagement>();
-            foreach (var item in yearDemands)
-            {
-                var routingOp = routingOps.Where(x => x.RoutingCode == item.SAPItemNumber).ToList();
-                //组装标准工时
-                var Assembly = routingOp.Where(x => x.Descr == "组装").FirstOrDefault();
-                //热封标准工时
-                var HeatSealing = routingOp.Where(x => x.Descr == "热封").FirstOrDefault();
-                //包装标准工时
-                var Packaging = routingOp.Where(x => x.Descr == "包装").FirstOrDefault();
-                var prodLine = prodLines.Where(x => x.Part == item.SAPItemNumber).OrderBy(x => x.Sequence).FirstOrDefault();
-                //不同库位库存数量
-                var locationList = locations.Where(x => x.ItemNum == item.SAPItemNumber).ToList();
-                //平台数据
-                var platformInvs = platformInvList.Where(x => x.SAPItemNumber == item.SAPItemNumber).ToList();
-                //销售预测 对应 Excel中公式 AVERAGE 如果预测为0不参与计算排产批量
-                var QtySum = yearDemands.Where(x => x.SAPItemNumber == item.SAPItemNumber && x.Qty > 0).ToList();
-                //排产批量:(AVG(1 - 12月销售预测)/ 100 )=(0.45 = 1 小数向上取整)  *100 = 100
-                var pcpl = Math.Ceiling(QtySum.Sum(p => p.Qty) / QtySum.Count()) * 100;
-                //库存合计 + 在制+已发货 + 灭菌中 TODO: 灭菌中取值待确定
-                var ship = shipList.Where(x => x.ContainerItem == item.SAPItemNumber).ToList();
-                var locationSum = (locationList.Count == 0 ? 0 : locationList.Sum(x => x.QtyOnHand)) + (platformInvs.Count == 0 ? 0 : platformInvs.Sum(x => x.InventoryQuantity)) + (ship.Count == 0 ? 0 : ship.Sum(x => x.RealQty)) + InProductionQty + 0;
-                //前面N个月的生产数量
-                var frontQtySum = annualProductionOutlines.Sum(x => x.Qty);
-                //生产数量:3月为例子,if((库存合计和前2月生产数量)-(前2个月销售预测数据+安全库存)-当月销售预测数据 / 2 < 0)
-                // { 排产批量 * ((-(库存合计+前2个月生产数量)) +  (安全库存+前2个月销售预测) + 当月销售预测 / 2 ) / 排产批量 ) } else {0}
-                decimal ProduceQty = 0.00m;
-                //判断库存是否满足需要,满足则不用生产
-                var num = (locationSum.Value + frontQtySum) - frontYearDemand.Sum(m => m.Qty) + 0 - item.Qty / 2;
-                if (num < 0)
-                {
-                    ProduceQty = pcpl * Math.Ceiling((-(locationSum.Value + frontQtySum)) + (frontYearDemand.Sum(m => m.Qty) + 0) + item.Qty / 2);
-                }
-                else
-                {
-                    ProduceQty = 0;
-                }
-
-                //生成年度生产大纲
-                AnnualProductionOutline annualProductionOutline = new AnnualProductionOutline();
-                annualProductionOutline.Year = item.Year;
-                annualProductionOutline.Area = item.Area;
-                annualProductionOutline.ProdLine = item.ProdLine;
-                annualProductionOutline.ProdRange = item.ProdRange;
-                annualProductionOutline.WorkshopLine = prodLine == null ? "" : prodLine.Line;
-                annualProductionOutline.SAPItemNumber = item.SAPItemNumber;
-                annualProductionOutline.Model = item.Model;
-                annualProductionOutline.Languages = item.Languages;
-                annualProductionOutline.PlanMonth = item.PlanMonth;
-                annualProductionOutline.Qty = ProduceQty;
-                annualProductionOutline.StandardHours = (Assembly == null ? 0 : Assembly.RunTime) + (HeatSealing == null ? 0 : HeatSealing.RunTime) + (Packaging == null ? 0 : Packaging.RunTime);
-                //组装热封包装工时乘以数量 =单月工时
-                annualProductionOutline.AssemblyHours = Assembly == null ? 0 : Assembly.RunTime * ProduceQty;
-                annualProductionOutline.HeatSealingHours = HeatSealing == null ? 0 : HeatSealing.RunTime * ProduceQty;
-                annualProductionOutline.PackagingHours = Packaging == null ? 0 : Packaging.RunTime * ProduceQty;
-                annualProductionOutline.Totalhours = annualProductionOutline.AssemblyHours + annualProductionOutline.HeatSealingHours + annualProductionOutline.Totalhours;
-                annualProductionOutline.OrderNum = item.OrderNum;
-                annualProductionOutlines.Add(annualProductionOutline);
-                frontYearDemand.Add(item);
-            }
-            //保存数据
-            using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
-            {
-                try
-                {
-                    //await _annualProductionOutline.InsertManyAsync(annualProductionOutlines);
-                    await unitOfWork.CompleteAsync();
-                }
-                catch (Exception e)
-                {
-                    unitOfWork.Dispose();
-                    new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveAnnualProductionOutline", "【" + input.year + "年" + "】年度生成大纲生成失败:" + e.Message, _currentTenant.Id.ToString());
-                    return "NO|" + e.Message;
-                };
-            }
-            return "OK";
-        }
-
-        /// <summary>
-        /// 生成主计划
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        public async Task<string> SaveProductionMasterPlan(InputDto input)
-        {
-            //计算当前年月的N0,N+1,N+2
-            List<string> planMons = new List<string>();
-            string strN0 = input.year.ToString() + "-" + input.month.ToString("00");
-            planMons.Add(strN0);
-            int newYear = input.month == 12 ? input.year + 1 : input.year;
-            int newMonth = input.month == 12 ? 1 : input.month + 1;
-            string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
-            planMons.Add(strN1);
-            newYear = newMonth == 12 ? newYear + 1 : newYear;
-            newMonth = newMonth == 12 ? 1 : newMonth + 1;
-            string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
-            planMons.Add(strN2);
-            //N0,N+1,N+2月度发货计划
-            var productionMasterPlan = _productionMasterPlan.GetListAsync(x => x.Year == input.year && !x.IsDeleted && x.tenant_id == input.tenant_id && x.company_id == input.company_id && x.factory_id == input.factory_id && planMons.Contains(x.PlanMonth)).Result.OrderBy(p => p.OrderNum).ThenBy(o => o.PlanMonth).ToList();
-            foreach (var item in productionMasterPlan)
-            {
-
-            }
-
-
-
-
-
-            //保存数据
-            using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
-            {
-                try
-                {
-                    //await _annualProductionOutline.InsertManyAsync(annualProductionOutlines);
-                    await unitOfWork.CompleteAsync();
-                }
-                catch (Exception e)
-                {
-                    unitOfWork.Dispose();
-                    new NLogHelper("AnnualProductionOutlineAppService").WriteLog("SaveProductionMasterPlan", "【" + input.year + "年" + "】主计划生成失败:" + e.Message, _currentTenant.Id.ToString());
-                    return "NO|" + e.Message;
-                };
-            }
-            return "OK";
-
-        }
-    }
-}

+ 0 - 1034
MicroServices/Business/Business.Application/SaleForecastManagement/MonthlyCapacityLoadAppService.cs

@@ -1,1034 +0,0 @@
-using Business.Core.Utilities;
-using Business.Domain;
-using Business.Dto;
-using Business.EntityFrameworkCore.SqlRepositories;
-using Business.SaleForecast;
-using Business.StructuredDB.WMS;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Volo.Abp.Application.Services;
-using Volo.Abp.DependencyInjection;
-using Volo.Abp.Domain.Repositories;
-using Volo.Abp.MultiTenancy;
-using Volo.Abp.Uow;
-
-namespace Business.SaleForecastManagement
-{
-    /// <summary>
-    /// 产能分析
-    /// </summary>
-    public class ReplenishmentAppService : ApplicationService, IMonthlyCapacityLoadAppService, ITransientDependency
-    {
-        #region 服务
-        /// <summary>
-        /// 物料
-        /// </summary>
-        private IRepository<ic_item, long> _ic_item;
-
-        /// <summary>
-        /// 生产线明细
-        /// </summary>
-        private ISqlRepository<ProdLineDetail> _prodLineDetail;
-
-        /// <summary>
-        /// 工作日历数据
-        /// </summary>
-        private ISqlRepository<ShopCalendarWorkCtr> _shopCalendarWorkCtr;
-
-        /// <summary>
-        /// 产线休息时间记录表
-        /// </summary>
-        private ISqlRepository<QualityLineWorkDetail> _qualityLineWorkDetail;
-
-        /// <summary>
-        /// 节假日记录表
-        /// </summary>
-        private ISqlRepository<HolidayMaster> _holidayMaster;
-
-        /// <summary>
-        /// 工作单元
-        /// </summary>
-        private readonly IUnitOfWorkManager _unitOfWorkManager;
-
-        /// <summary>
-        /// 日志
-        /// </summary>
-        private readonly ICurrentTenant _currentTenant;
-
-        /// <summary>
-        /// 年度生产需求大纲
-        /// </summary>
-        private IRepository<YearDemandManagement, long> _yearDemandManagement;
-
-        /// <summary>
-        /// 年度生产需求大纲历史记录
-        /// </summary>
-        private IRepository<YearDemandManagementHistory, long> _yearDemandManagementHistory;
-
-        /// <summary>
-        /// 国内终端预测
-        /// </summary>
-        private IRepository<DomesticTerminalFcst, long> _domesticTerminalFcst;
-
-        /// <summary>
-        /// 海外销售预测
-        /// </summary>
-        private IRepository<OverseasSaleFcst, long> _overseasSaleFcst;
-
-        /// <summary>
-        /// 平台预测收集
-        /// </summary>
-        private IRepository<PlatformFcstCollect, long> _platformFcstCollect;
-
-        /// <summary>
-        /// 标准物料规格型号设置表
-        /// </summary>
-        private IRepository<StandardItemModelSet,long> _standardItemModelSet;
-
-        /// <summary>
-        /// 库存明细表
-        /// </summary>
-        private ISqlRepository<LocationDetail> _locationDetail;
-
-        /// <summary>
-        /// 工单
-        /// </summary>
-        private ISqlRepository<WorkOrdMaster> _workOrdMaster;
-
-        /// <summary>
-        /// 整体需求计划
-        /// </summary>
-        private IRepository<OverallDemandPlan, long> _overallDemandPlan;
-
-        /// <summary>
-        /// 月度产能共识表
-        /// </summary>
-        private IRepository<MonthlyProdCapacity, long> _monthlyProdCapacity;
-
-        /// <summary>
-        /// 月度产能共识明细表
-        /// </summary>
-        private IRepository<MonthlyProdCapacityDtl, long> _monthlyProdCapacityDtl;
-
-        /// <summary>
-        /// SKU版本维护表
-        /// </summary>
-        private IRepository<SkuVersionSet, long> _skuVersionSet;
-
-        /// <summary>
-        /// 计划订单表
-        /// </summary>
-        private IRepository<crm_planorder, long> _crm_planorder;
-
-        /// <summary>
-        /// 平台库存监控月份
-        /// </summary>
-        private IRepository<PlatStockMonitorSetting, long> _platStockMonitorSetting;
-
-        /// <summary>
-        /// 平台库存表
-        /// </summary>
-        private IRepository<WMS_PlatformInventory, long> _platformInventory;
-
-        /// <summary>
-        /// 参数设置表
-        /// </summary>
-        private ISqlRepository<GeneralizedCodeMaster> _generalizedCodeMaster;
-
-        /// <summary>
-        /// SAP库存表
-        /// </summary>
-        private ISqlRepository<SAPInv> _SAPInv;
-
-        /// <summary>
-        /// 雪花算法
-        /// </summary>
-        SnowFlake help = new SnowFlake();
-        #endregion
-
-        #region 构造函数
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        public ReplenishmentAppService(
-            IRepository<ic_item, long> ic_item,
-            ISqlRepository<ProdLineDetail> prodLineDetail,
-            ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
-            ISqlRepository<QualityLineWorkDetail> qualityLineWorkDetail,
-            ISqlRepository<HolidayMaster> holidayMaster,
-            IRepository<MonthlyProdCapacity, long> monthlyProdCapacity,
-            IUnitOfWorkManager unitOfWorkManager,
-            ICurrentTenant currentTenant,
-            IRepository<StandardItemModelSet,long> standardItemModelSet,
-            IRepository<YearDemandManagement, long> yearDemandManagement,
-            IRepository<DomesticTerminalFcst, long> domesticTerminalFcst,
-            IRepository<OverseasSaleFcst, long> overseasSaleFcst,
-            IRepository<PlatformFcstCollect, long> platformFcstCollect,
-            IRepository<YearDemandManagementHistory, long> yearDemandManagementHistory,
-            ISqlRepository<LocationDetail> locationDetail,
-            ISqlRepository<WorkOrdMaster> workOrdMaster,
-            IRepository<OverallDemandPlan, long> overallDemandPlan,
-            IRepository<MonthlyProdCapacityDtl, long> monthlyProdCapacityDtl,
-            IRepository<SkuVersionSet, long> skuVersionSet,
-            IRepository<crm_planorder, long> crm_planorder,
-            IRepository<PlatStockMonitorSetting, long> platStockMonitorSetting,
-            IRepository<WMS_PlatformInventory, long> platformInventory,
-            ISqlRepository<GeneralizedCodeMaster> generalizedCodeMaster,
-            ISqlRepository<SAPInv> SAPInv
-            )
-        {
-            _ic_item = ic_item;
-            _prodLineDetail = prodLineDetail;
-            _shopCalendarWorkCtr = shopCalendarWorkCtr;
-            _qualityLineWorkDetail = qualityLineWorkDetail;
-            _holidayMaster = holidayMaster;
-            _monthlyProdCapacity = monthlyProdCapacity;
-            _unitOfWorkManager = unitOfWorkManager;
-            _currentTenant = currentTenant;
-            _standardItemModelSet = standardItemModelSet;
-            _yearDemandManagement= yearDemandManagement;
-            _domesticTerminalFcst= domesticTerminalFcst;
-            _overseasSaleFcst = overseasSaleFcst;
-            _platformFcstCollect= platformFcstCollect;
-            _yearDemandManagementHistory= yearDemandManagementHistory;
-            _locationDetail = locationDetail;
-            _workOrdMaster = workOrdMaster;
-            _overallDemandPlan = overallDemandPlan;
-            _monthlyProdCapacityDtl = monthlyProdCapacityDtl;
-            _skuVersionSet= skuVersionSet;
-            _crm_planorder= crm_planorder;
-            _platStockMonitorSetting = platStockMonitorSetting;
-            _platformInventory = platformInventory;
-            _generalizedCodeMaster = generalizedCodeMaster;
-            _SAPInv = SAPInv;
-        }
-        #endregion
-
-        /// <summary>
-        /// 月度需求预测更新
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        /// <exception cref="NotImplementedException"></exception>
-        public async Task<string> DemandAnalysis(InputDto input)
-        {
-            //1.0 获取当前年年度生产需求大纲
-            List<YearDemandManagement> yearDemands = _yearDemandManagement.GetListAsync(p => p.Year == input.year && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p=>p.OrderNum).ToList();
-            //1.0 获取下一年年度生产大纲
-            List<YearDemandManagement> nextYearDemands = _yearDemandManagement.GetListAsync(p => p.Year == (input.year+1) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
-            //记录历史版本:当前年+下一年
-            var updateMonth = input.year.ToString() + "-" + input.month.ToString("00");
-            var histories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(yearDemands);
-            histories.ForEach(p => {
-                p.UpdateMonth = updateMonth;
-            });
-            var nextHistories = ObjectMapper.Map<List<YearDemandManagement>, List<YearDemandManagementHistory>>(nextYearDemands);
-            nextHistories.ForEach(p => {
-                p.UpdateMonth = updateMonth;
-            });
-            //1.1、获取海外销售预测数据
-            List<OverseasSaleFcst> overseasSales = _overseasSaleFcst.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.2、获取平台预测收集数据
-            List<PlatformFcstCollect> platformFcsts = _platformFcstCollect.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.3、获取国内终端预测-T1汇总数据
-            List<DomesticTerminalFcst> domesticFcst = _domesticTerminalFcst.GetListAsync(p =>p.TypeEnum == 2 && p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.3.1、获取T2-海王,T2-国科数据
-            List<DomesticTerminalFcst> T2Fcsts = _domesticTerminalFcst.GetListAsync(p => (p.TypeEnum == 4 || p.TypeEnum == 5) && p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.4、根据年度生产大纲,获取规格型号对应的补货周期
-            List<string> allModels = yearDemands.Select(p=>p.Model).Distinct().ToList();
-            if (nextYearDemands.Any())
-            {
-                allModels.AddRange(nextYearDemands.Select(p => p.Model).ToList());
-                allModels = allModels.Distinct().ToList();
-            }
-            List<StandardItemModelSet> standards = _standardItemModelSet.GetListAsync(p => allModels.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.5、获取规格型号对应的标准SKU数据:获取最小包装单位
-            List<string> itemNums = standards.Select(p=>p.ItemNumber).Distinct().ToList();
-            List<ic_item> items = _ic_item.GetListAsync(p=> itemNums.Contains(p.number) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.6、获取成品库存、灭菌库存、在制库存(会从SAP同步的库存表更新到LocationDetail、ic_item表中)
-            //List<SAPInv> sAPInvs = _SAPInv.Select(p => p.WERKS == input.factory_id.ToString() && itemNums.Contains(p.MATNR));
-            List<LocationDetail> locations = _locationDetail.Select(p => p.Domain == input.factory_id.ToString() && itemNums.Contains(p.ItemNum) && p.IsActive);
-            //1.7、获取节假日设置
-            List<HolidayMaster> holidays = _holidayMaster.Select(p => (p.Dated.Value.Year == input.year || p.Dated.Value.Year == (input.year + 1)) && p.Domain == input.factory_id.ToString() && p.IsActive);
-            //1.8、获取平台库存监控月份设置
-            List<PlatStockMonitorSetting> monitorSettings = _platStockMonitorSetting.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //1.9、获取客户要求交期在N+1月的销售订单
-            //List<>
-            #region 数据校验
-            //1、校验当前年的年度生产大纲是否导入
-            if (!yearDemands.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
-                return "NO|请导入" + input.year + "年的年度生产需求后再操作!";
-            }
-            //2、如果当前月份大于10,则需校验下一年的年度生产大纲
-            if (input.month > 10 && !nextYearDemands.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + (input.year+1) + "年的年度生产需求后再操作!", _currentTenant.Id.ToString());
-                return "NO|请导入" + (input.year + 1) + "年的年度生产需求后再操作!";
-            }
-            //3、校验当前月份的海外销售预测是否导入
-            if (!overseasSales.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!", _currentTenant.Id.ToString());
-                return "NO|请导入" + input.year + "年" + input.month + "月海外销售预测后再操作!";
-            }
-            //4、校验当前月份的平台预测收集是否导入
-            if (!platformFcsts.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!", _currentTenant.Id.ToString());
-                return "NO|请导入" + input.year + "年" + input.month + "月平台需求收集后再操作!";
-            }
-            //5、校验当前月份的国内终端预测是否导入
-            if (!domesticFcst.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!", _currentTenant.Id.ToString());
-                return "NO|请导入" + input.year + "年" + input.month + "月国内终端预测后再操作!";
-            }
-            //6、校验终端+平台导入的规格型号是否已维护标准SKU
-            if (allModels.Count() != standards.Count())
-            {
-                allModels.RemoveAll(standards.Select(p=>p.Model).ToList());
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",",allModels) + "】没有维护标准SKU,请维护后再操作!", _currentTenant.Id.ToString());
-                return "NO|规格型号【" + string.Join(",", allModels) + "】没有维护标准SKU,请维护后再操作!";
-            }
-            //7、校验是否已维护补货周期
-            var zeros = standards.Where(p => p.ReplenishCycle == 0).ToList();
-            if (zeros.Any())
-            {
-                new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "规格型号【" + string.Join(",", zeros.Select(p=>p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!", _currentTenant.Id.ToString());
-                return "NO|规格型号【" + string.Join(",", zeros.Select(p => p.Model).ToList()) + "】没有维护补货周期,请维护后再操作!";
-            }
-            #endregion
-
-            //计算当前年月的N0,N+1,N+2
-            List<string> planMons = new List<string>();
-            int newYear = input.month == 12 ? input.year + 1 : input.year;
-            int newMonth = input.month == 12 ? 1 : input.month + 1;
-            string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
-            planMons.Add(strN1);
-            newYear = newMonth == 12 ? newYear + 1 : newYear;
-            newMonth = newMonth == 12 ? 1 : newMonth + 1;
-            string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
-            planMons.Add(strN2);
-
-            //需要回写的数据
-            List<YearDemandManagement> updates = new List<YearDemandManagement>();
-            #region 计算国内终端预测,回写年度生产大纲
-            //获取导入的T1、平台数据
-            List<string> gnModels = new List<string>();
-            if (domesticFcst.Any())
-            {
-                gnModels.AddRange(domesticFcst.Select(p => p.Model).ToList());
-            }
-            if (platformFcsts.Any())
-            {
-                gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
-            }
-            gnModels = gnModels.Distinct().ToList();
-            foreach (var gnModel in gnModels)
-            {
-                //N+1月
-                YearDemandManagement monthN1 = new YearDemandManagement();
-                //N+2月
-                YearDemandManagement monthN2 = new YearDemandManagement();
-                //获取需要回写的数据
-                if (input.month < 11)
-                {
-                    monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
-                    monthN2 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
-                }
-                if (input.month == 11)
-                {
-                    monthN1 = yearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
-                    monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
-                }
-                if (input.month == 12)
-                {
-                    monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN1);
-                    monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "国内" && p.Model == gnModel && p.PlanMonth == strN2);
-                }
-                if (monthN1 == null || monthN2 == null)
-                {
-                    continue;
-                }
-                //T1
-                var sumT1N1 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p=>p.Qty);
-                var sumT1N2 = domesticFcst.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
-                //平台
-                var sumPN1 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN1).Sum(p => p.Qty);
-                var sumPN2 = platformFcsts.Where(p => p.Model == gnModel && p.PlanMonth == strN2).Sum(p => p.Qty);
-                //合计
-                var sumN1 = sumT1N1+ sumPN1;
-                var sumN2 = sumT1N2 + sumPN2;
-
-                //当前规格型号对应标准SKU的最小包装单位、补货周期
-                var curStd = standards.FirstOrDefault(p => p.Model == gnModel);
-                decimal packQty = 1m;//最小包装单位
-                decimal cycle = 0m;//补货周期
-                //获取成品库存、在制库存、灭菌库存,参与计算
-                decimal cpQty = 0m;
-                decimal zzQty = 0m;
-                decimal mjQty = 0m;
-                if (curStd != null)
-                {
-                    var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
-                    packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
-                    cycle = curStd.ReplenishCycle;
-                    //成品库存
-                    cpQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "8001").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                    //在制库存
-                    zzQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "8000").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                    //灭菌库存
-                    mjQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "5008").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                }
-                //N+1月使用N+2月的再订货点参与计算
-                decimal rop = CalcRop(strN2+"-01", sumN2, packQty, holidays, cycle);
-                monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 + rop - cpQty - zzQty - mjQty) / packQty) * packQty;
-                //N+2月使用本月的需求量,下一月的工作天数
-                rop = CalcRop(Convert.ToDateTime(strN2 + "-01").AddMonths(1).ToString("yyyy-MM-dd"), sumN2, packQty, holidays, cycle);
-                monthN2.Qty = Math.Ceiling((sumN2 + rop - cpQty - zzQty - mjQty) / packQty) * packQty;
-                //负数置0
-                monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
-                monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
-                //记录需要回写的数据
-                updates.Add(monthN1);
-                updates.Add(monthN2);
-            }
-            #endregion
-
-            #region 海外销售预测,回写年度生产大纲
-            List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
-            foreach (var hwModel in hwModels)
-            {
-                //N+1月
-                YearDemandManagement monthN1 = new YearDemandManagement();
-                //N+2月
-                YearDemandManagement monthN2 = new YearDemandManagement();
-                //获取需要回写的数据
-                if (input.month < 11)
-                {
-                    monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
-                    monthN2 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
-                }
-                if (input.month == 11)
-                {
-                    monthN1 = yearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
-                    monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
-                }
-                if (input.month == 12)
-                {
-                    monthN1 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN1);
-                    monthN2 = nextYearDemands.FirstOrDefault(p => p.Area == "海外" && p.Model == hwModel && p.PlanMonth == strN2);
-                }
-                if (monthN1 == null || monthN2 == null) {
-                    continue;
-                }
-                var sumN1 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN1).Sum(p => p.Qty);
-                var sumN2 = overseasSales.Where(p => p.Model == hwModel && p.PlanMonth == strN2).Sum(p => p.Qty);
-
-                //当前规格型号对应标准SKU的最小包装单位、补货周期
-                var curStd = standards.FirstOrDefault(p => p.Model == hwModel);
-                decimal packQty = 1m;//最小包装单位
-                //获取成品库存、在制库存、灭菌库存,参与计算
-                decimal cpQty = 0m;
-                decimal zzQty = 0m;
-                decimal mjQty = 0m;
-                if (curStd != null)
-                {
-                    var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
-                    packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
-                    //成品库存
-                    cpQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "8001").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                    //在制库存
-                    zzQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "8000").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                    //灭菌库存
-                    mjQty = locations.Where(p => p.ItemNum == curStd.ItemNumber && p.Location == "5008").Sum(p => Convert.ToDecimal(p.QtyOnHand));
-                }
-                //海外生产需求量=当月的50%+下一月的50%-成品库存-在制库存-灭菌库存
-                //TODO:获取成品库存、在制库存、灭菌库存,参与运算
-                //计算N+1月,N+2月
-                monthN1.Qty = Math.Ceiling((sumN1 / 2 + sumN2 / 2 - cpQty - zzQty - mjQty) / packQty) * packQty;
-                monthN2.Qty = Math.Ceiling((sumN2 - cpQty - zzQty - mjQty) / packQty) *packQty; ;
-                //负数置0
-                monthN1.Qty = monthN1.Qty < 0 ? 0m : monthN1.Qty;
-                monthN2.Qty = monthN2.Qty < 0 ? 0m : monthN2.Qty;
-                //记录需要回写的数据
-                updates.Add(monthN1);
-                updates.Add(monthN2);
-            }
-            #endregion
-
-            //生成月度产能共识
-            var capacityDto = CapacityAnalysis(input, updates, planMons);
-
-            //生成下一个月的补货计划
-            var nextMonPFcsts = platformFcsts.Where(p => p.PlanMonth == strN2).ToList();
-            var nextMonDFcsts = domesticFcst.Where(p => p.PlanMonth == strN2).ToList();
-            var nextMonT2Fcsts = T2Fcsts.Where(p => p.PlanMonth == strN2).ToList();
-            var nextMonMonitors = monitorSettings.Where(p => p.PlanMonth == strN1).ToList();
-            var replenishs = MonthlyReplenish(input,strN1, nextMonPFcsts, nextMonDFcsts, nextMonT2Fcsts, standards, items, holidays, nextMonMonitors, locations);
-
-            //保存数据
-            using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
-            {
-                try
-                {
-                    //判断是否存在当前年月的历史版本,不存在则插入
-                    var dbHistory =  _yearDemandManagementHistory.GetListAsync(p=>p.Year ==input.year && p.UpdateMonth == updateMonth && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
-                    if (!dbHistory.Any())
-                    {
-                        await _yearDemandManagementHistory.InsertManyAsync(histories);
-                    }
-                    if (input.month > 10)
-                    {
-                        //判断是否存在下一年月的历史版本,不存在则插入
-                        dbHistory = _yearDemandManagementHistory.GetListAsync(p =>(p.Year == input.year + 1) && p.UpdateMonth == updateMonth && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
-                        if (!dbHistory.Any())
-                        {
-                            await _yearDemandManagementHistory.InsertManyAsync(nextHistories);
-                        }
-                    }
-                    //回写年度生产大纲
-                    await _yearDemandManagement.UpdateManyAsync(updates);
-                    //先删除产能共识、产能共识明细
-                    await _monthlyProdCapacity.HardDeleteAsync(p=>p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
-                    await _monthlyProdCapacityDtl.HardDeleteAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
-                    await _monthlyProdCapacity.InsertManyAsync(capacityDto.mains);
-                    await _monthlyProdCapacityDtl.InsertManyAsync(capacityDto.details);
-                    //生成下一月的补货计划
-                    await _crm_planorder.HardDeleteAsync(p=>p.PlanMonth == strN1 && p.Source =="系统运算" && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
-                    await _crm_planorder.InsertManyAsync(replenishs);
-
-                    await unitOfWork.CompleteAsync();
-                }
-                catch (Exception e)
-                {
-                    unitOfWork.Dispose();
-                    new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "【" + input.year + "年" + input.month + "月】月度需求预测更新失败:" + e.Message, _currentTenant.Id.ToString());
-                    return "NO|" + e.Message;
-                };
-            }
-            return "OK|刷新成功!";
-        }
-
-        /// <summary>
-        /// 生成月度产能共识
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        public MonthlyCapacityDto CapacityAnalysis(InputDto input,List<YearDemandManagement> yearDemands, List<string> planMons)
-        {
-            //1、获取数据
-            //1.1 根据规格型号获取物料数据
-            List<string> models = yearDemands.Select(p => p.Model).Distinct().ToList();
-            List<StandardItemModelSet> standards = _standardItemModelSet.GetListAsync(p => models.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id).Result;
-            //1.3 根据物料编码获取产线数据
-            List<ProdLineDetail> lineDtls = _prodLineDetail.Select(p => standards.Select(m => m.ItemNumber).Contains(p.Part) && p.Domain == input.factory_id.ToString() && p.IsActive).OrderBy(p => p.Line).ToList();
-            //1.4 根据产线获取工作日历数据和产线休息配置数据
-            List<ShopCalendarWorkCtr> calendars = _shopCalendarWorkCtr.Select(p => lineDtls.Select(m => m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
-            List<QualityLineWorkDetail> lineWorks = _qualityLineWorkDetail.Select(p => lineDtls.Select(m => m.Line).Contains(p.ProdLine) && p.Domain == input.factory_id.ToString() && p.IsActive);
-            //1.5 获取当前年和下一年的节假日配置数据
-            List<HolidayMaster> holidays = _holidayMaster.Select(p => (p.Dated.Value.Year == input.year || p.Dated.Value.Year == (input.year + 1)) && p.Domain == input.factory_id.ToString() && p.IsActive);
-
-            //月度产能共识表
-            List<MonthlyProdCapacity> capacities = new List<MonthlyProdCapacity>();
-            //月度产能共识明细表
-            List<MonthlyProdCapacityDtl> capacityDtls = new List<MonthlyProdCapacityDtl>();
-
-            //产线
-            List<string> lines = lineDtls.Select(p => p.Line).Distinct().ToList();
-            foreach (var item in lines)
-            {
-                //计算每天工作时间
-                var curCal = calendars.FirstOrDefault(p => p.ProdLine == item);
-                if (curCal == null)
-                {
-                    continue;
-                }
-                foreach (var pm in planMons)
-                {
-                    //添加月度产能共识产能效率数据
-                    MonthlyProdCapacity dtl = new MonthlyProdCapacity();
-                    dtl.Year = input.year;
-                    dtl.Month = input.month;
-                    dtl.PlanMonth = pm;
-                    dtl.ProdLine = item;
-
-                    dtl.DailyWorks = curCal.ShiftsHours1 + curCal.ShiftsHours2 + curCal.ShiftsHours3 + curCal.ShiftsHours4;
-                    dtl.FlightQty = 1;
-                    //计算当月工作天数
-                    var curHoildays = holidays.Where(p => p.Dated.Value.Year == Convert.ToInt16(pm.Substring(0,4)) && p.Dated.Value.Month == Convert.ToInt16(pm.Substring(5, 2))).ToList();
-                    //当月天数
-                    int days = DateTime.DaysInMonth(input.year, input.month);
-                    //当月周末天数
-                    int weekDays = CalcWeekDays(days, Convert.ToDateTime(pm + "-01"));
-                    dtl.MonthWorks = days - weekDays - curHoildays.Where(p => p.Ufld1 == "休假").Count() + curHoildays.Where(p => p.Ufld1 == "调班").Count();
-                    dtl.AvailableTimes = dtl.DailyWorks * dtl.MonthWorks;
-                    //计算产线耗时
-                    var curLines = lineDtls.Where(p => p.Line == item).ToList();
-                    decimal sumTimes = 0.00m;
-                    List<ProdLineDto> lineDtos = new List<ProdLineDto>(); 
-                    foreach (var ld in curLines)
-                    {
-                        if (lineDtos.Exists(p=>p.Part == ld.Part && p.Line == ld.Line))
-                        {
-                            continue;
-                        }
-                        var curStand = standards.FirstOrDefault(p => p.ItemNumber == ld.Part);
-                        if (curStand == null)
-                        {
-                            continue;
-                        }
-                        var curDemands = yearDemands.Where(p => p.Model == curStand.Model && p.PlanMonth == pm).ToList();
-                        var line = curLines.Where(p=>p.Part == ld.Part && p.Line == ld.Line).OrderByDescending(p => p.Op).First();
-                        sumTimes += line.Rate == 0 ? 0 : (Math.Ceiling(curDemands.Sum(p => p.Qty) / line.Rate));
-
-                        MonthlyProdCapacityDtl capacityDtl = new MonthlyProdCapacityDtl();
-                        capacityDtl.Year = input.year;
-                        capacityDtl.Month = input.month;
-                        capacityDtl.PlanMonth = pm;
-                        capacityDtl.ProdLine = item;
-                        capacityDtl.Model = curStand.Model;
-                        capacityDtl.Qty = curDemands.Sum(p => p.Qty);
-                        capacityDtl.tenant_id = input.tenant_id;
-                        capacityDtl.company_id = input.company_id;
-                        capacityDtl.factory_id = input.factory_id;
-                        capacityDtl.org_id = input.org_id;
-                        capacityDtl.create_by = input.create_by;
-                        capacityDtl.create_by_name = input.create_by_name;
-                        capacityDtl.create_time = DateTime.Now;
-                        capacityDtls.Add(capacityDtl);
-
-                        lineDtos.Add(new ProdLineDto { 
-                            Part = ld.Part,
-                            Line= ld.Line
-                        });
-                    }
-
-                    dtl.NeedWorks = sumTimes;
-                    dtl.ProdRate = 100;
-                    dtl.Rate = dtl.AvailableTimes == 0 ? 0 : Math.Floor(dtl.NeedWorks / dtl.AvailableTimes * 100);
-                    dtl.IsOverTime = dtl.NeedWorks > dtl.AvailableTimes ? "是" : "否";
-                    dtl.OverTimes = dtl.IsOverTime == "是" ? (dtl.NeedWorks - dtl.AvailableTimes) : 0;
-                    dtl.tenant_id = input.tenant_id;
-                    dtl.company_id= input.company_id;
-                    dtl.factory_id = input.factory_id;
-                    dtl.org_id= input.org_id;
-                    dtl.create_by= input.create_by;
-                    dtl.create_by_name = input.create_by_name;
-                    dtl.create_time = DateTime.Now;
-                    capacities.Add(dtl);
-                }
-            }
-            return new MonthlyCapacityDto{ 
-                mains = capacities,
-                details = capacityDtls
-            };
-        }
-
-        /// <summary>
-        /// T1、平台自动补货
-        /// </summary>
-        /// <param name="input"></param>
-        /// <param name="strN1">计划补货月份:N+1月</param>
-        /// <param name="platformFcsts">平台预测</param>
-        /// <param name="domesticFcsts">T1预测</param>
-        /// <param name="standards">标准SKU设置</param>
-        /// <param name="items">物料</param>
-        /// <param name="holidays">节假日</param>
-        /// <param name="monitorSettings">库存监控月份设置</param>
-        /// <param name="locations">SAP同步库存</param>
-        /// <returns></returns>
-        public List<crm_planorder> MonthlyReplenish(InputDto input,string strN1, List<PlatformFcstCollect> platformFcsts, List<DomesticTerminalFcst> domesticFcsts, List<DomesticTerminalFcst> T2Fcsts, List<StandardItemModelSet> standards, List<ic_item> items, List<HolidayMaster> holidays, List<PlatStockMonitorSetting> monitorSettings, List<LocationDetail> locations)
-        { 
-            List<crm_planorder> planorders = new List<crm_planorder>();
-            //获取T1中规格型号对应的不同版本的物料编码
-            var T1Models = domesticFcsts.Select(p => p.Model).Distinct().ToList();
-            List<SkuVersionSet> skus = _skuVersionSet.GetListAsync(p=> T1Models.Contains(p.Model) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result;
-            //获取T1库存
-            //List<string> itemNums = skus.Select(p=>p.ItemNum).Distinct().ToList();
-            //List<LocationDetail> locationDetails = _locationDetail.Select(p=> itemNums.Contains(p.ItemNum) && p.Domain == input.factory_id.ToString() && p.IsActive);
-
-            //获取临期库存设置
-            GeneralizedCodeMaster master = _generalizedCodeMaster.Select(p => p.Domain == input.factory_id.ToString() && p.IsActive && p.Val == "LongPeriodItemPlanMonth").FirstOrDefault();
-            int month = master == null ? 0 : Convert.ToInt16(master.UDeci1);
-            DateTime strTime = Convert.ToDateTime(platformFcsts[0].PlanMonth + "-01").AddMonths(month);
-            //获取平台库存
-            var PModels = platformFcsts.Select(p => p.Model).Distinct().ToList();
-            List<WMS_PlatformInventory> pInventories = _platformInventory.GetListAsync(p=> PModels.Contains(p.SpecificationModel) && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && p.PeriodOfValidity >= strTime).Result;
-            
-            //计算T1补货
-            foreach (var item in T1Models)
-            {
-                //获取当前规格型号对应的预测数据
-                var curFcsts = domesticFcsts.Where(p=>p.Model == item).ToList();
-                //当前规格型号对应的库存数量
-                decimal sumQty = 0.00m;
-                //当前的物料版本
-                var curSkus = skus.Where(p => p.Model == item).ToList();
-                if (curSkus.Any())
-                {
-                    //sumQty = sAPInvs.Where(p => curSkus.Select(p => p.ItemNum).Contains(p.MATNR)).Sum(p => Convert.ToDecimal(p.LABST));
-                    sumQty = locations.Where(p => curSkus.Select(p => p.ItemNum).Contains(p.ItemNum) && p.Location == "8001").Sum(p => p.QtyOnHand);
-                }
-                //计算Rop
-                //当前规格型号对应标准SKU的最小包装单位、补货周期
-                var curStd = standards.FirstOrDefault(p => p.Model == item);
-                decimal packQty = 1m;//最小包装单位
-                decimal cycle = 0m;//补货周期
-                if (curStd != null)
-                {
-                    var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
-                    packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
-                    cycle = curStd.ReplenishCycle;
-                }
-                //N+1月使用N+2月的再订货点参与计算
-                decimal rop = CalcRop(curFcsts[0].PlanMonth + "-01", curFcsts.Sum(p=>p.Qty), packQty, holidays, cycle);
-                if(sumQty < rop)
-                {
-                    planorders.Add(new crm_planorder { 
-                        PlanMonth = strN1,
-                        Model = curFcsts[0].Model,
-                        ItemNum = curStd?.ItemNumber,
-                        ProdLine = curFcsts[0].ProdLine,
-                        ProdType = "",
-                        Qty = rop,
-                        Type = "计划单-T1直发补货"
-                    });
-                }
-            }
-
-            //计算平台补货:海王
-            var hwFcsts = platformFcsts.Where(p => p.Platform == "海王").ToList();
-            var hwModels = hwFcsts.Select(p=>p.Model).Distinct().ToList();
-            foreach (var item in hwModels)
-            {
-                //获取当前规格型号对应的平台预测数据
-                var curFcsts = hwFcsts.Where(p => p.Model == item).ToList();
-                //当前规格型号对应的库存数量
-                decimal sumQty = 0.00m;
-                //当前规格型号对应标准SKU的最小包装单位、补货周期
-                var curStd = standards.FirstOrDefault(p => p.Model == item);
-                decimal packQty = 1m;//最小包装单位
-                decimal cycle = 0m;//补货周期
-                if (curStd != null)
-                {
-                    var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
-                    packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
-                    cycle = curStd.ReplenishCycle;
-                }
-                //T2海王预测数据
-                var curT2Hws = T2Fcsts.Where(p => p.Model == item && p.TypeEnum == 4).ToList();
-                //计算Rop:N+1月使用N+2月的再订货点参与计算
-                decimal rop = CalcRop(curFcsts[0].PlanMonth + "-01", curT2Hws.Sum(p => p.Qty), packQty, holidays, cycle);
-                //获取海王当前规格型号库存
-                sumQty = pInventories.Where(p => p.SpecificationModel == item && p.Code == "HW0001").Sum(p=>p.InventoryQuantity);
-                //获取N+1月的库存监控设置
-                var curMonitor = monitorSettings.FirstOrDefault(p => p.Platform == "海王" && p.ProdType == curFcsts[0].ProdType);
-                if (curMonitor == null)
-                {
-                    new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "海王未维护产品类型为【"+ curFcsts[0].ProdType + "】的库存监控月份", _currentTenant.Id.ToString());
-                    continue;
-                }
-                //最小覆盖月份库存
-                var minQty = rop * curMonitor.MinTimes;
-                //最大库存月份库存
-                var maxQty = rop * curMonitor.MaxTimes;
-                //需补货数量
-                decimal needQty = 0m;
-                if (sumQty >= minQty && sumQty < maxQty)//大于等于最低库存覆盖月,小于最高库存覆盖月
-                {
-                    planorders.Add(new crm_planorder
-                    {
-                        PlanMonth = strN1,
-                        Model = curFcsts[0].Model,
-                        ItemNum = curStd?.ItemNumber,
-                        ProdLine = curT2Hws[0].ProdLine,
-                        ProdType = "",
-                        Qty = maxQty - sumQty,
-                        Type = "计划单-T2平台补货"
-                    });
-                }
-                if (sumQty < minQty)//低于最低库存覆盖月
-                {
-                    while (sumQty < minQty) 
-                    {
-                        sumQty += rop;
-                        needQty += rop;
-                    }
-                    planorders.Add(new crm_planorder
-                    {
-                        PlanMonth = strN1,
-                        Model = curFcsts[0].Model,
-                        ItemNum = curStd?.ItemNumber,
-                        ProdLine = curT2Hws[0].ProdLine,
-                        ProdType = "",
-                        Qty = needQty,
-                        Type = "计划单-T2平台补货"
-                    });
-                }
-            }
-
-            //计算平台补货:国科
-            var gkFcsts = platformFcsts.Where(p => p.Platform == "国科").ToList();
-            var gkModels = gkFcsts.Select(p => p.Model).Distinct().ToList();
-            foreach (var item in gkModels)
-            {
-                //获取当前规格型号对应的预测数据
-                var curFcsts = gkFcsts.Where(p => p.Model == item).ToList();
-                //当前规格型号对应的库存数量
-                decimal sumQty = 0.00m;
-                //当前规格型号对应标准SKU的最小包装单位、补货周期
-                var curStd = standards.FirstOrDefault(p => p.Model == item);
-                decimal packQty = 1m;//最小包装单位
-                decimal cycle = 0m;//补货周期
-                if (curStd != null)
-                {
-                    var curItem = items.FirstOrDefault(p => p.number == curStd.ItemNumber);
-                    packQty = curItem == null ? 1 : (curItem.minpackqty.GetValueOrDefault() == 0.0m ? 1 : curItem.minpackqty.Value);
-                    cycle = curStd.ReplenishCycle;
-                }
-                //T2国科预测数据
-                var curT2Gks = T2Fcsts.Where(p => p.Model == item && p.TypeEnum == 5).ToList();
-                //计算Rop:N+1月使用N+2月的再订货点参与计算
-                decimal rop = CalcRop(curFcsts[0].PlanMonth + "-01", curT2Gks.Sum(p => p.Qty), packQty, holidays, cycle);
-                //获取国科当前规格型号库存
-                sumQty = pInventories.Where(p => p.SpecificationModel == item && p.Code == "GK0001").Sum(p => p.InventoryQuantity);
-                //获取N+1月的库存监控设置
-                var curMonitor = monitorSettings.FirstOrDefault(p => p.Platform == "国科" && p.ProdType == curFcsts[0].ProdType);
-                if (curMonitor == null)
-                {
-                    new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("DemandAnalysis", "国科未维护产品类型为【" + curFcsts[0].ProdType + "】的库存监控月份", _currentTenant.Id.ToString());
-                    continue;
-                }
-                //最小覆盖月份库存
-                var minQty = rop * curMonitor.MinTimes;
-                //最大库存月份库存
-                var maxQty = rop * curMonitor.MaxTimes;
-                //需补货数量
-                decimal needQty = 0m;
-                if (sumQty >= minQty && sumQty < maxQty)
-                {
-                    planorders.Add(new crm_planorder
-                    {
-                        PlanMonth = strN1,
-                        Model = curFcsts[0].Model,
-                        ItemNum = curStd?.ItemNumber,
-                        ProdLine = curT2Gks[0].ProdLine,
-                        ProdType = "",
-                        Qty = maxQty - sumQty,
-                        Type = "计划单-T2平台补货"
-                    });
-                }
-                if (sumQty < minQty)
-                {
-                    while (sumQty < minQty)
-                    {
-                        sumQty += rop;
-                        needQty += rop;
-                    }
-                    planorders.Add(new crm_planorder
-                    {
-                        PlanMonth = strN1,
-                        Model = curFcsts[0].Model,
-                        ItemNum = curStd?.ItemNumber,
-                        ProdLine = curT2Gks[0].ProdLine,
-                        ProdType = "",
-                        Qty = needQty,
-                        Type = "计划单-T2平台补货"
-                    });
-                }
-            }
-
-            planorders.ForEach(p => {
-                p.Source = "系统运算";
-                p.tenant_id = input.tenant_id;
-                p.company_id = input.company_id;
-                p.factory_id = input.factory_id;
-                p.org_id = input.org_id;
-                p.create_by = input.create_by;
-                p.create_by_name = input.create_by_name;
-                p.create_time = DateTime.Now;
-            });
-            return planorders;
-        }
-
-
-        /// <summary>
-        /// 计算再订货点
-        /// </summary>
-        /// <param name="planMonth">计划年月(yyyy-MM-dd)</param>
-        /// <param name="qty">需求量</param>
-        /// <param name="qty">最小包装数量</param>
-        /// <param name="holidays">节假日</param>
-        /// <param name="replenishCycle">补货周期</param>
-        /// <returns></returns>
-        private decimal CalcRop(string planMonth,decimal qty,decimal packQty,List<HolidayMaster> holidays,decimal replenishCycle)
-        {
-            decimal rop = 0.0m;
-            //获取当月天数
-            int year = Convert.ToInt16(planMonth.Substring(0, 4));
-            int month = Convert.ToInt16(planMonth.Substring(5, 2));
-            int days = DateTime.DaysInMonth(year, month);
-            //计算当前月的周末天数
-            int weeks = CalcWeekDays(days, Convert.ToDateTime(planMonth));
-            //获取当前年月的节假日设置
-            var curHolidays = holidays.Where(p => p.Dated.Value.Year == year && p.Dated.Value.Month == month).ToList();
-            //当月工作天数
-            int workDays = days - weeks - curHolidays.Where(p => p.Ufld1 == "休假").Count() + curHolidays.Where(p => p.Ufld1 == "调班").Count();
-            //rop = (需求量/月工作天数*补货周期)=>按照最小包装单位元整
-            rop = Math.Ceiling(qty / workDays * replenishCycle / packQty) * packQty;
-            return rop;
-        }
-
-        /// <summary>
-        /// 计算当月有多少个周末
-        /// </summary>
-        /// <param name="days"></param>
-        /// <param name="startDay"></param>
-        /// <returns></returns>
-        private int CalcWeekDays(int days, DateTime startDay)
-        {
-            int sumDays = 0;
-            for (int i = 0; i < days; i++)
-            {
-                int weekDays = (int)startDay.AddDays(i).DayOfWeek;
-                if (weekDays == 0 || weekDays == 6)
-                {
-                    sumDays++;
-                }
-            }
-            return sumDays;
-        }
-
-        /// <summary>
-        /// 生成整体需求计划
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        /// <exception cref="NotImplementedException"></exception>
-        public async Task<string> OverallDemandPlan(InputDto input)
-        {
-            //1.1、获取海外销售预测数据
-            List<OverseasSaleFcst> overseasSales = _overseasSaleFcst.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
-            //1.2、获取平台预测收集数据
-            List<PlatformFcstCollect> platformFcsts = _platformFcstCollect.GetListAsync(p => p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p=>p.OrderNum).ToList();
-            //1.3、获取国内终端预测-T1汇总数据
-            List<DomesticTerminalFcst> domesticFcsts = _domesticTerminalFcst.GetListAsync(p => p.TypeEnum == 2 && p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id && !p.IsDeleted).Result.OrderBy(p => p.OrderNum).ToList();
-
-            //计算当前年月的N+1,N+2
-            string strN0 = input.year.ToString() + "-" + input.month.ToString("00");
-            int newYear = input.month == 12 ? input.year + 1 : input.year;
-            int newMonth = input.month == 12 ? 1 : input.month + 1;
-            string strN1 = newYear.ToString() + "-" + newMonth.ToString("00");
-            newYear = newMonth == 12 ? newYear + 1 : newYear;
-            newMonth = newMonth == 12 ? 1 : newMonth + 1;
-            string strN2 = newYear.ToString() + "-" + newMonth.ToString("00");
-
-            //整体需求计划
-            List<OverallDemandPlan> plans = new List<OverallDemandPlan>();
-            //计算海外
-            List<string> hwModels = overseasSales.Select(p => p.Model).Distinct().ToList();
-            int OrderNum = 1;
-            foreach (var item in hwModels)
-            {
-                var curFcsts = overseasSales.Where(p => p.Model == item).ToList();
-                OverallDemandPlan plan = new OverallDemandPlan();
-                plan.Area = "海外";
-                plan.Model = item;
-                plan.PlanMonth = strN0;
-                plan.Qty = curFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                plan = new OverallDemandPlan();
-                plan.Area = "海外";
-                plan.Model = item;
-                plan.PlanMonth = strN1;
-                plan.Qty = curFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                plan = new OverallDemandPlan();
-                plan.Area = "海外";
-                plan.Model = item;
-                plan.PlanMonth = strN2;
-                plan.Qty = curFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                OrderNum += 1;
-            }
-            //计算国内
-            List<string> gnModels = domesticFcsts.Select(p=>p.Model).ToList();
-            gnModels.AddRange(platformFcsts.Select(p => p.Model).ToList());
-            gnModels = gnModels.Distinct().ToList();
-            OrderNum = 1;
-            foreach (var item in gnModels)
-            {
-                var curDFcsts = domesticFcsts.Where(p => p.Model == item).ToList();
-                var curPFcsts = platformFcsts.Where(p => p.Model == item).ToList();
-                OverallDemandPlan plan = new OverallDemandPlan();
-                plan.Area = "国内";
-                plan.Model = item;
-                plan.PlanMonth = strN0;
-                plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN0).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                plan = new OverallDemandPlan();
-                plan.Area = "国内";
-                plan.Model = item;
-                plan.PlanMonth = strN1;
-                plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN1).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                plan = new OverallDemandPlan();
-                plan.Area = "国内";
-                plan.Model = item;
-                plan.PlanMonth = strN2;
-                plan.Qty = curDFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty) + curPFcsts.Where(p => p.PlanMonth == strN2).Sum(p => p.Qty);
-                plan.OrderNum = OrderNum;
-                plans.Add(plan);
-
-                OrderNum += 1;
-            }
-
-            plans.ForEach(p => {
-                p.Year= input.year;
-                p.Month= input.month;
-                p.tenant_id = input.tenant_id;
-                p.company_id = input.company_id;
-                p.factory_id= input.factory_id;
-                p.org_id= input.org_id;
-                p.create_by = input.create_by;
-                p.create_by_name= input.create_by_name;
-                p.create_time = DateTime.Now;
-            });
-
-            //保存数据
-            using (var unitOfWork = _unitOfWorkManager.Begin(false, true))
-            {
-                try
-                {
-                    //先删除
-                    await _overallDemandPlan.HardDeleteAsync(p=>p.Year == input.year && p.Month == input.month && p.tenant_id == input.tenant_id && p.company_id == input.company_id && p.factory_id == input.factory_id);
-                    //保存整体需求计划
-                    await _overallDemandPlan.InsertManyAsync(plans);
-                    await unitOfWork.CompleteAsync();
-                }
-                catch (Exception e)
-                {
-                    unitOfWork.Dispose();
-                    new NLogHelper("MonthlyCapacityLoadAppService").WriteLog("OverallDemandPlan", "生成【" + input.year + "年" + input.month + "月】整体需求计划失败:" + e.Message, _currentTenant.Id.ToString());
-                    return "NO|" + e.Message;
-                };
-            }
-            return "OK|刷新成功!";
-        }
-    }
-}

+ 3 - 1
MicroServices/Business/Business.Domain/MongoDB/MES/IC/mo_ic_item.cs

@@ -686,8 +686,10 @@ namespace Business.Domain
         /// <summary>
         /// 供应提前期
         /// </summary>
-        [StringLength(80)]
         [Comment("供应提前期")]
+        [Required]
+        [DefaultValue(0)]
+        [Precision(23, 10)]
         public int PurLT { get; set; }
     }
 }

+ 3 - 1
MicroServices/Business/Business.Domain/StructuredDB/MES/IC/ic_item.cs

@@ -691,8 +691,10 @@ namespace Business.Domain
         /// <summary>
         /// 供应提前期
         /// </summary>
-        [StringLength(80)]
         [Comment("供应提前期")]
+        [Required]
+        [DefaultValue(0)]
+        [Precision(23, 10)]
         public int PurLT { get; set; }
     }
 }

+ 2 - 2
MicroServices/Business/Business.Domain/StructuredDB/SaleFcst/AnnualProductionOutline.cs → MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentAnnualProduction.cs

@@ -5,13 +5,13 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace Business.StructuredDB.SaleFcst
+namespace Business.StructuredDB.Replenishment
 {
 
     /// <summary>
     ///  年度生产大纲    
     /// </summary>
-    public class AnnualProductionOutline : BaseEntity
+    public class ReplenishmentAnnualProduction : BaseEntity
     {
         /// <summary>
         /// 年    

+ 176 - 0
MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentMonthPlan.cs

@@ -0,0 +1,176 @@
+using Business.Domain;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.StructuredDB.Replenishment
+{
+
+    /// <summary>
+    ///  月生产主计划    
+    /// </summary>
+    public class ReplenishmentMonthPlan : BaseEntity
+    {
+        /// <summary>
+        /// 市场    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("市场")]
+        public string Area { get; set; }
+
+        /// <summary>
+        /// 产品线    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("产品线")]
+        public string ProdLine { get; set; }
+
+        /// <summary>
+        /// 产品系列    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("产品系列")]
+        public string ProdRange { get; set; }
+
+        /// <summary>
+        /// 车间线体(产线)    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("车间线体(产线)    ")]
+        public string Line { get; set; }
+
+        /// <summary>
+        /// 物料编码   
+        /// </summary>
+        [StringLength(128)]
+        [Comment("物料编码")] 
+        public string ItemNumber { get; set; }
+
+        /// <summary>
+        /// 规格型号    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("规格型号")] 
+        public string Model { get; set; }
+
+        /// <summary>
+        /// 生命周期    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("产品线")]
+        public string LifeCycle { get; set; }
+
+        /// <summary>
+        /// 语种    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("语种")]
+        public string Languages { get; set; }
+
+        /// <summary>
+        /// 计划年月    
+        /// </summary>
+        [StringLength(7)]
+        [Comment("计划年月")] 
+        public string PlanMonth { get; set; }
+
+        /// <summary>
+        /// 计划发货数量    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("计划发货数量")] 
+        public decimal PlanShipQty { get; set; }
+
+        /// <summary>
+        /// 实际发货数量    
+        /// </summary>
+
+        [Precision(18, 5)]
+        [Comment("实际发货数量")] 
+        public decimal ActualShipQty { get; set; }
+
+
+        /// <summary>
+        /// 8001库存(灭菌完成检验合格转入的仓库)    
+        /// </summary>
+
+        [Precision(18, 5)]
+        [Comment("8001库存(灭菌完成检验合格转入的仓库)")] 
+        public decimal Inventory8001 { get; set; }
+
+
+        /// <summary>
+        /// 8000库存(委外灭菌仓)    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("8000库存(委外灭菌仓)")] 
+        public decimal Inventory8000 { get; set; }
+
+        /// <summary>
+        /// 5008库存(成品线边仓)    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("5008库存(成品线边仓)")] 
+        public decimal Inventory5008 { get; set; }
+
+        /// <summary>
+        /// 灭菌中数量    
+        /// </summary>
+        [Precision(18, scale: 5)]
+        [Comment("灭菌中数量")] 
+        public decimal DuringSterilizationQty { get; set; }
+
+        /// <summary>
+        /// 在制数量    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("在制数量")] 
+        public decimal InProductionQty { get; set; }
+
+        /// <summary>
+        /// 计划生产数量    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("计划生产数量")]
+        public decimal PlanProductQty { get; set; }
+
+        /// <summary>
+        /// 实际生产数量    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("实际生产数量")]
+        public decimal ActualProductQty { get; set; }
+
+        
+        /// <summary>
+        /// 期初库存    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("期初库存")] 
+        public decimal StartStockQty { get; set; }
+
+        /// <summary>
+        /// 期末库存    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("期末库存")] 
+        public decimal EndStockQty { get; set; }
+
+        /// <summary>
+        /// 经济批量    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("经济批量")] 
+        public decimal EconomicLotQty { get; set; }
+
+        /// <summary>
+        /// 排序编码    
+        /// </summary>
+        [Comment("排序编码")]
+        public int OrderNum { get; set; }
+    }
+}

+ 3 - 3
MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentModel.cs → MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentROP.cs

@@ -11,11 +11,11 @@ using ZstdSharp.Unsafe;
 namespace Business.Domain
 {
     /// <summary>
-    ///补货模型算法表
+    ///补货模型ROP
     /// </summary>
-    [Comment("补货模型算法表")]
+    [Comment("补货模型ROP")]
     [Index(nameof(number), nameof(tenant_id), nameof(fversion),nameof(long_period),nameof(short_period),nameof(isparam), nameof(seqno),nameof(zero_based_seqno), nameof(factory_id), IsUnique = true)]
-    public class ReplenishmentModel : BaseEntity
+    public class ReplenishmentROP : BaseEntity
     {
         /// <summary>
         /// 物料编码

+ 3 - 3
MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ItemABCFMR.cs → MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentServiceLevel.cs

@@ -11,11 +11,11 @@ using ZstdSharp.Unsafe;
 namespace Business.Domain
 {
     /// <summary>
-    ///补货模型物料abcfmr
+    ///补货模型物料Z服务水平
     /// </summary>
     [Comment("补货模型物料abcfmr")]
     [Index(nameof(number), nameof(tenant_id), nameof(fversion),nameof(isstandalone), nameof(factory_id), IsUnique = true)]
-    public class replenishmentabcfmr : BaseEntity
+    public class ReplenishmentServiceLevel : BaseEntity
     {
         /// <summary>
         /// 物料编码
@@ -118,7 +118,7 @@ namespace Business.Domain
         /// <summary>
         /// 是否独立计算,成品跟产品计算,原材料跟原材料计算
         /// </summary>
-        [Comment("Z服务水平参数")]
+        [Comment("是否独立计算,成品跟产品计算,原材料跟原材料计算")]
         public bool isstandalone { get; set; }
     }
 }

+ 193 - 0
MicroServices/Business/Business.Domain/StructuredDB/Replenishment/ReplenishmentWeekPlan.cs

@@ -0,0 +1,193 @@
+using Business.Domain;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.StructuredDB.Replenishment
+{
+
+    /// <summary>
+    ///  周生产计划    
+    /// </summary>
+    public class ReplenishmentWeekPlan : BaseEntity
+    {
+        /// <summary>
+        /// 排序编码(优先级)    
+        /// </summary>
+        [Comment("排序编码(优先级)")]
+        public int OrderNum { get; set; }
+
+        /// <summary>
+        /// 市场    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("市场")]
+        public string Area { get; set; }
+
+        /// <summary>
+        /// 开工日期
+        /// </summary>
+        [Comment("开工日期")]
+        public DateTime PlanStartDate { get; set; }
+
+        /// <summary>
+        /// 开工日期星期
+        /// </summary>
+        [StringLength(128)]
+        [Comment("开工日期星期")]
+        public string Week { get; set; }
+
+        /// <summary>
+        /// 订单号
+        /// </summary>
+        [StringLength(128)]
+        [Comment("订单号")]
+        public string OrderNO { get; set; }
+
+        /// <summary>
+        /// 生产指令
+        /// </summary>
+        [StringLength(128)]
+        [Comment("生产指令")]
+        public string ProductionOrder { get; set; }
+
+        /// <summary>
+        /// SAP工单号
+        /// </summary>
+        [StringLength(128)]
+        [Comment("SAP工单号")]
+        public string SAPOrderNO { get; set; }
+
+
+        /// <summary>
+        /// 指令类型
+        /// </summary>
+        [StringLength(128)]
+        [Comment("指令类型")]
+        public string OrderType { get; set; }
+
+        /// <summary>
+        /// 生产批次
+        /// </summary>
+        [StringLength(128)]
+        [Comment("生产批次")]
+        public string ProductionBatch { get; set; }
+
+        /// <summary>
+        /// 生产状态
+        /// </summary>
+        [StringLength(128)]
+        [Comment("生产状态")]
+        public string ProductionStatus { get; set; }
+
+        /// <summary>
+        /// 产品线    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("产品线")]
+        public string ProdLine { get; set; }
+
+        /// <summary>
+        /// 产品系列    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("产品系列")]
+        public string ProdRange { get; set; }
+
+        /// <summary>
+        /// 车间线体(产线)    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("车间线体(产线)")]
+        public string Line { get; set; }
+
+        /// <summary>
+        /// 物料编码   
+        /// </summary>
+        [StringLength(128)]
+        [Comment("物料编码")]
+        public string ItemNumber { get; set; }
+
+        /// <summary>
+        /// 规格型号    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("规格型号")]
+        public string Model { get; set; }
+
+        /// <summary>
+        /// 语种    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("语种")]
+        public string Languages { get; set; }
+
+        /// <summary>
+        /// 计划数量    
+        /// </summary>
+        [Precision(18,5)]
+        [Comment("计划数量")]
+        public decimal Qty { get; set; }
+
+        /// <summary>
+        /// 物料情况    
+        /// </summary>
+        [StringLength(128)]
+        [Comment("物料情况")]
+        public string ItemStatus { get; set; }
+
+        /// <summary>
+        /// 预计齐套时间    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("预计齐套时间")]
+        public DateTime PlanKittingDate { get; set; }
+
+        /// <summary>
+        /// 灭菌开始日期    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("灭菌开始日期")]
+        public DateTime SterilizationDate { get; set; }
+
+
+        /// <summary>
+        /// 成品入库日期    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("成品入库日期")]
+        public DateTime InStockDate { get; set; }
+
+        /// <summary>
+        /// 组装工时    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("组装工时")]
+        public decimal AssembleHours { get; set; }
+
+        /// <summary>
+        /// 热封工时    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("热封工时")]
+        public decimal HeatSealHours { get; set; }
+
+        /// <summary>
+        /// 包装工时    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("包装工时")]
+        public decimal PackageHours { get; set; }
+
+        /// <summary>
+        /// 总工时    
+        /// </summary>
+        [Precision(18, 5)]
+        [Comment("包装工时")]
+        public decimal TotalHours { get; set; }
+    }
+}

+ 2 - 2
MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/BusinessDbContextModelCreatingExtensions.cs

@@ -283,9 +283,9 @@ namespace Business.EntityFrameworkCore
                 b.ConfigureByConvention();
             });
 
-            builder.Entity<ReplenishmentModel>(b =>
+            builder.Entity<ReplenishmentROP>(b =>
             {
-                b.ToTable("replenishmentmodel");
+                b.ToTable("ReplenishmentROP");
                 b.HasIndex(b => new { b.number, b.zero_based_seqno, b.long_period, b.short_period, b.tenant_id, b.company_id, b.factory_id });
                 b.ConfigureByConvention();
             });

+ 4 - 3
MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/DOP/BusinessDbContext.cs

@@ -1,6 +1,7 @@
 using Business.Domain;
 using Business.StructuredDB.MES;
 using Business.StructuredDB.Production;
+using Business.StructuredDB.Replenishment;
 using Business.StructuredDB.SaleFcst;
 using Business.StructuredDB.WMS;
 using Microsoft.EntityFrameworkCore;
@@ -224,7 +225,7 @@ namespace Business.EntityFrameworkCore
         /// <summary>
         /// 年度生产大纲
         /// </summary>
-        public DbSet<AnnualProductionOutline> AnnualProductionOutline { get; set; }
+        public DbSet<ReplenishmentAnnualProduction> ReplenishmentAnnualProduction { get; set; }
 
         /// <summary>
         /// 主生产计划
@@ -258,7 +259,7 @@ namespace Business.EntityFrameworkCore
 
         public DbSet<WMS_PlatformSpecificationComparison> WMS_PlatformSpecificationComparison { get; set; }
 
-        public DbSet<ReplenishmentModel> ReplenishmentModel { get; set; }
+        public DbSet<ReplenishmentROP> ReplenishmentROP { get; set; }
 
         public DbSet<ASNBOLShipperDetail> ASNBOLShipperDetail { get; set; }
 
@@ -269,7 +270,7 @@ namespace Business.EntityFrameworkCore
         /// </summary>
         public DbSet<SAPInv> SAPInv { get; set; }
 
-        public DbSet<replenishmentabcfmr> replenishmentabcfmr { get; set; }
+        public DbSet<ReplenishmentServiceLevel> ReplenishmentServiceLevel { get; set; }
 
         #endregion
 

+ 0 - 47
MicroServices/Business/Business.HttpApi/Controllers/AnnualProductionOutlineController.cs

@@ -1,47 +0,0 @@
-using Business.Dto;
-using Business.SaleForecast;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Volo.Abp;
-
-namespace Business.Controllers
-{
-    /// <summary>
-    /// 年度生产大纲
-    /// </summary>
-    [RemoteService]
-    [Area("Business")]
-    [Route("api/business/AnnualProductionOutline")]
-    public class AnnualProductionOutlineController
-    {
-        /// <summary>
-        /// 年度生产大纲
-        /// </summary>
-        private readonly IAnnualProductionOutlineAppService _IAnnualProductionOutlineAppService;
-
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        /// <param name="MonthlyCapacityLoadAppService"></param>
-        public AnnualProductionOutlineController(IAnnualProductionOutlineAppService MonthlyCapacityLoadAppService)
-        {
-            _IAnnualProductionOutlineAppService = MonthlyCapacityLoadAppService;
-        }
-        /// <summary>
-        /// 月度需求分析
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        [HttpPost]
-        [Route("SaveAnnualProductionOutline")]
-        public Task<string> SaveAnnualProductionOutline(InputDto input)
-        {
-            return _IAnnualProductionOutlineAppService.SaveAnnualProductionOutline(input);
-        }
-
-    }
-}

+ 0 - 73
MicroServices/Business/Business.HttpApi/Controllers/MonthlyCapacityLoadController.cs

@@ -1,73 +0,0 @@
-using Business.Dto;
-using Business.ResourceExamineManagement;
-using Business.SaleForecast;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Volo.Abp;
-using Volo.Abp.AspNetCore.Mvc;
-
-namespace Business.Controllers
-{
-    /// <summary>
-    /// 月度产能分析接口
-    /// </summary>
-    [RemoteService]
-    [Area("Business")]
-    [Route("api/business/monthly_capacity_load")]
-    public class MonthlyCapacityLoadController:AbpController
-    {
-        /// <summary>
-        /// 产能分析接口
-        /// </summary>
-        private readonly IMonthlyCapacityLoadAppService _MonthlyCapacityLoadAppService;
-
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        /// <param name="MonthlyCapacityLoadAppService"></param>
-        public MonthlyCapacityLoadController(IMonthlyCapacityLoadAppService MonthlyCapacityLoadAppService)
-        {
-            _MonthlyCapacityLoadAppService = MonthlyCapacityLoadAppService;
-        }
-
-        ///// <summary>
-        ///// 产能分析
-        ///// </summary>
-        ///// <param name="input"></param>
-        ///// <returns></returns>
-        //[HttpPost]
-        //[Route("capacityanalysis")]
-        //public Task<string> CapacityAnalysis(InputDto input)
-        //{
-        //    return _MonthlyCapacityLoadAppService.CapacityAnalysis(input);
-        //}
-
-        /// <summary>
-        /// 月度需求分析
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        [HttpPost]
-        [Route("demandanalysis")]
-        public Task<string> DemandAnalysis(InputDto input)
-        {
-            return _MonthlyCapacityLoadAppService.DemandAnalysis(input);
-        }
-
-        /// <summary>
-        /// 生成整体需求计划
-        /// </summary>
-        /// <param name="input"></param>
-        /// <returns></returns>
-        [HttpPost]
-        [Route("overalldemandplan")]
-        public Task<string> OverallDemandPlan(InputDto input)
-        {
-            return _MonthlyCapacityLoadAppService.OverallDemandPlan(input);
-        }
-    }
-}

+ 70 - 20
MicroServices/Business/Business.HttpApi/Controllers/ReplenishmentController.cs

@@ -33,17 +33,6 @@ namespace Business.Controllers
             _ReplenishmentAppService = ReplenishmentAppService;
         }
 
-        ///// <summary>
-        ///// 计划工单齐套检查
-        ///// </summary>
-        ///// <param name="workOrd"></param>
-        ///// <returns></returns>
-        //[HttpPost]
-        //[Route("PlanOrderResourceCheck")]
-        //public Task<string> PlanOrderResourceCheck(string companyid)
-        //{
-        //    return _ReplenishmentAppService.PlanOrderResourceCheck(companyid);
-        //}
 
         /// <summary>
         /// 调整ROP和最高库存水位
@@ -57,16 +46,77 @@ namespace Business.Controllers
             return _ReplenishmentAppService.CalcROP(input);
         }
 
-        ///// <summary>
-        ///// 更新周计划
-        ///// </summary>
-        ///// <param name="input"></param>
-        ///// <returns></returns>
-        //[HttpPost]
-        //[Route("weekplan")]
-        //public Task<string> WeekPlan(InputDto input)
+        /// <summary>
+        /// 生产周计划
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [Route("calcweekplan")]
+        public Task<string> CalcWeekPlan(InputDto input)
+        {
+            return _ReplenishmentAppService.CalcWeekPlan(input);
+        }
+
+
+        /// <summary>
+        /// 刷新年度销售预测
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [Route("demandanalysis")]
+        public Task<string> DemandAnalysis(InputDto input)
+        {
+            return _ReplenishmentAppService.DemandAnalysis(input);
+        }
+
+        /// <summary>
+        /// 定时任务长周期物料
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpGet]
+        [Route("calclongperioditempr")]
+        public Task<string> CalcLongPeriodItemPR(InputDto input)
+        {
+            return _ReplenishmentAppService.CalcLongPeriodItemPR(input);
+        }
+
+        /// <summary>
+        /// 定时任务每天补货
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpGet]
+        [Route("calcdayplan")]
+        public Task<string> CalcDayPlan(InputDto input)
+        {
+            return _ReplenishmentAppService.CalcDayPlan(input);
+        }
+
+        /// <summary>
+        /// 生成整体需求计划
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [Route("overalldemandplan")]
+        //public Task<string> OverallDemandPlan(InputDto input)
         //{
-        //    return _ReplenishmentAppService.WeekPlan(input);
+        //    return _ReplenishmentAppService.OverallDemandPlan(input);
         //}
+
+        /// <summary>
+        /// 年度生产大纲
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        [HttpPost]
+        [Route("SaveAnnualProductionOutline")]
+        public Task<string> SaveAnnualProductionOutline(InputDto input)
+        {
+            return _ReplenishmentAppService.SaveAnnualProductionOutline(input);
+        }
     }
 }

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 60 - 0
MicroServices/Business/QuartzSettings/logs/logs.txt


+ 1 - 1
MicroServices/Business/QuartzSettings/task_job.json

@@ -1 +1 @@
-[{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","Interval":"0 32 15 * * ?","ApiUrl":"http://123.60.180.165:8028/api/business/systemquartzjob/syncwmsdatatomysql","Describe":"系统定时任务,勿删勿动","LastRunTime":null,"Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":4,"timeflag":null,"changetime":null},{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","Interval":"0 01 01 * * ?","ApiUrl":"http://123.60.180.165:8028/api/business/systemquartzjob/loginstall","Describe":"系统定时任务,勿删勿动","LastRunTime":null,"Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":5,"timeflag":null,"changetime":null},{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","Interval":"0 04 17 * * ?","ApiUrl":"http://localhost:51186/api/business/systemquartzjob/syncbasedatatomongodb","Describe":"系统定时任务,勿删勿动","LastRunTime":"2023-07-04T17:03:12","Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":6,"timeflag":null,"changetime":null}]
+[{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","Interval":"0 32 15 * * ?","ApiUrl":"http://123.60.180.165:8028/api/business/systemquartzjob/syncwmsdatatomysql","Describe":"系统定时任务,勿删勿动","LastRunTime":null,"Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":4,"timeflag":null,"changetime":null},{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","Interval":"0 01 01 * * ?","ApiUrl":"http://123.60.180.165:8028/api/business/systemquartzjob/loginstall","Describe":"系统定时任务,勿删勿动","LastRunTime":null,"Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":5,"timeflag":null,"changetime":null},{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","Interval":"0 04 17 * * ?","ApiUrl":"http://localhost:51186/api/business/systemquartzjob/syncbasedatatomongodb","Describe":"系统定时任务,勿删勿动","LastRunTime":"2023-07-04T17:03:12","Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":6,"timeflag":null,"changetime":null},{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","Interval":"0 0 0 14 * ?","ApiUrl":"http://localhost:51186/api/business/replenishment/calclongperioditempr?year= 0&month= 0&tenant_id= 1000&company_id= 1000&factory_id= 1001&org_id= 1001","Describe":"系统定时任务,勿删勿动","LastRunTime":"2023-09-06T00:29:05","Status":6,"TaskType":2,"ApiRequestType":"GET","ApiAuthKey":null,"ApiAuthValue":null,"ApiParameter":null,"DllClassName":null,"DllActionName":null,"id":7,"timeflag":null,"changetime":null}]

+ 51 - 0
MicroServices/DopInterfacePlatform/ClientIpCheckActionFilter.cs

@@ -0,0 +1,51 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Net;
+
+namespace WebApiTest
+{
+    public class ClientIpCheckActionFilter : ActionFilterAttribute
+    {
+        private readonly ILogger _logger;
+        private readonly string _safelist;
+
+        public ClientIpCheckActionFilter(string safelist, ILogger logger)
+        {
+            _safelist = safelist;
+            _logger = logger;
+        }
+
+        public override void OnActionExecuting(ActionExecutingContext context)
+        {
+            var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
+            _logger.LogDebug("Remote IpAddress: {RemoteIp}", remoteIp);
+            var ip = _safelist.Split(';');
+            var badIp = true;
+
+            if (remoteIp.IsIPv4MappedToIPv6)
+            {
+                remoteIp = remoteIp.MapToIPv4();
+            }
+
+            foreach (var address in ip)
+            {
+                var testIp = IPAddress.Parse(address);
+
+                if (testIp.Equals(remoteIp))
+                {
+                    badIp = false;
+                    break;
+                }
+            }
+
+            if (badIp)
+            {
+                _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", remoteIp);
+                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
+                return;
+            }
+
+            base.OnActionExecuting(context);
+        }
+    }
+}

+ 40 - 0
MicroServices/DopInterfacePlatform/Controllers/TokenController.cs

@@ -0,0 +1,40 @@
+using DopInterfacePlatform.Interface;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Options;
+using System.Security.Claims;
+
+namespace DopInterfacePlatform.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class TokenController : ControllerBase
+    {
+        public IJwtService _jwtService { set; get; }
+
+        private IConfiguration _configuration;
+        public TokenController(IJwtService jwtService, IConfiguration configuration)
+        {
+            _jwtService = jwtService;
+            _configuration = configuration;
+        }
+
+        [AllowAnonymous]
+        [HttpGet]
+        [Route("token")]
+        public string GetToken()
+        {
+            JwtOptions jwtOptions=new JwtOptions();
+            jwtOptions.ExpireSeconds = Convert.ToInt32(_configuration["JWT:ExpireSeconds"]);
+            jwtOptions.Issuer = _configuration["JWT:Issuer"];
+            jwtOptions.Audience = _configuration["JWT:Audience"];
+            jwtOptions.Key = _configuration["JWT:Key"];
+            List<Claim> claims = new List<Claim>();
+            claims.Add(new Claim(ClaimTypes.Name, "用户1"));
+            claims.Add(new Claim(ClaimTypes.Role, "超级管理员"));
+            return _jwtService.BuildToken(claims, jwtOptions);
+        }
+    }
+}

+ 73 - 0
MicroServices/DopInterfacePlatform/Controllers/WeatherForecastController.cs

@@ -0,0 +1,73 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.ServiceModel;
+using System.Xml;
+
+namespace DopInterfacePlatform.Controllers
+{
+    [ApiController]
+    [Route("[controller]/[action]")]
+    [Authorize]
+    public class WeatherForecastController : ControllerBase
+    {
+        private static readonly string[] Summaries = new[]
+        {
+        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+    };
+
+        private readonly ILogger<WeatherForecastController> _logger;
+
+        public WeatherForecastController(ILogger<WeatherForecastController> logger)
+        {
+            _logger = logger;
+        }
+
+        [HttpGet(Name = "GetWeatherForecast")]
+        [Authorize]
+        public IEnumerable<WeatherForecast> Get()
+        {
+            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
+            {
+                Date = DateTime.Now.AddDays(index),
+                TemperatureC = Random.Shared.Next(-20, 55),
+                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
+            })
+            .ToArray();
+        }
+
+        [HttpGet(Name = "GetByCount")]
+        [Authorize]
+        public int GetByCount(int count)
+        {
+            return count+7;
+        }
+
+
+        [HttpGet(Name = "GetByCount1")]
+        [Authorize]
+        public int GetByCount1(int count,int count2)
+        {
+            return count + 7+count2;
+        }
+
+        [HttpGet(Name = "TestWebservice")]
+        [Authorize]
+        public string TestWebservice()
+        {
+            var parameters = new Dictionary<string, string> { { "byProvinceName", "湖北" } };
+            HttpContent httpContent = new FormUrlEncodedContent(parameters);
+
+            // contentType对应 webservice提示 如下图
+            httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
+            HttpClient httpClient = new HttpClient();
+            HttpResponseMessage response = httpClient.PostAsync("http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getSupportCity", httpContent).Result;
+            var statusCode = response.StatusCode.ToString();
+            var result = response.Content.ReadAsStringAsync().Result;
+            var doc = new XmlDocument();
+            doc.LoadXml(result);
+            // xml返回值数据所在标签,替换成你的xml结果标签,如下图
+            var status = doc.InnerXml;
+            return status;
+        }
+    }
+}

+ 23 - 0
MicroServices/DopInterfacePlatform/DopInterfacePlatform.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <Nullable>enable</Nullable>
+    <ImplicitUsings>enable</ImplicitUsings>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.21" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.21" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.21" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.21">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
+    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.32.2" />
+    <PackageReference Include="System.ServiceModel.Http" Version="6.0.0" />
+  </ItemGroup>
+
+</Project>

+ 8 - 0
MicroServices/DopInterfacePlatform/DopInterfacePlatform.csproj.user

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Controller_SelectedScaffolderID>ApiControllerEmptyScaffolder</Controller_SelectedScaffolderID>
+    <Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
+    <NameOfLastUsedPublishProfile>D:\DOPCore\MicroServices\DOPInterfacePlatform\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
+  </PropertyGroup>
+</Project>

+ 25 - 0
MicroServices/DopInterfacePlatform/DopInterfacePlatform.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33205.214
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DopInterfacePlatform", "DopInterfacePlatform.csproj", "{58B598BA-29FC-492E-A976-D271F3A842C8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{58B598BA-29FC-492E-A976-D271F3A842C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58B598BA-29FC-492E-A976-D271F3A842C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58B598BA-29FC-492E-A976-D271F3A842C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58B598BA-29FC-492E-A976-D271F3A842C8}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {7F2B40AE-DFBA-4D9F-B6CB-01281BA69379}
+	EndGlobalSection
+EndGlobal

+ 14 - 0
MicroServices/DopInterfacePlatform/DopInterfacePlatformContext.cs

@@ -0,0 +1,14 @@
+using DopInterfacePlatform.Entity;
+using Microsoft.EntityFrameworkCore;
+
+namespace DopInterfacePlatform
+{
+    public class DopInterfacePlatformContext: DbContext
+    {
+        public DbSet<InterfacePlatformLog> InterfacePlatformLog { get; set; }
+        public DopInterfacePlatformContext(DbContextOptions<DopInterfacePlatformContext> options)
+           : base(options)
+        {
+        }
+    }
+}

+ 49 - 0
MicroServices/DopInterfacePlatform/Entity/InterfacePlatformLog.cs

@@ -0,0 +1,49 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+using System.Security.Principal;
+
+namespace DopInterfacePlatform.Entity
+{
+    [Table("InterfacePlatformLog")]
+    public class InterfacePlatformLog
+    {
+        [Key]
+        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+        public Int64 operatorcol_id { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:False
+        /// </summary>           
+        public string operatorcol_ip { get; set; }
+
+        /// <summary>
+        /// Desc:调用入参
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string operatorcol_request { get; set; }
+
+        /// <summary>
+        /// Desc:调用出参
+        /// Default:
+        /// Nullable:True
+        /// </summary>           
+        public string operatorcol_respone { get; set; }
+
+        /// <summary>
+        /// Desc:
+        /// Default:
+        /// Nullable:False
+        /// </summary>           
+        public DateTime operatorcol_time { get; set; }
+
+        /// <summary>
+        /// Desc:调用接口耗时,单位为毫秒
+        /// Default:
+        /// Nullable:False
+        /// </summary>           
+        public int operatorcol_duration { get; set; }
+    }
+}

+ 9 - 0
MicroServices/DopInterfacePlatform/Interface/IJwtService.cs

@@ -0,0 +1,9 @@
+using System.Security.Claims;
+
+namespace DopInterfacePlatform.Interface
+{
+    public interface IJwtService
+    {
+        string BuildToken(IEnumerable<Claim> claims, JwtOptions options);
+    }
+}

+ 55 - 0
MicroServices/DopInterfacePlatform/IpWhiteListMiddleware.cs

@@ -0,0 +1,55 @@
+using System.Net;
+
+namespace DopInterfacePlatform
+{
+    public class IpWhiteListMiddleware
+    {
+        private readonly RequestDelegate _next;
+        private readonly ILogger<IpWhiteListMiddleware> _logger;
+        private readonly string _adminSafeList;
+
+        public IpWhiteListMiddleware(
+            RequestDelegate next,
+            ILogger<IpWhiteListMiddleware> logger,
+            string adminSafeList)
+        {
+            _adminSafeList = adminSafeList;
+            _next = next;
+            _logger = logger;
+        }
+
+        public async Task Invoke(HttpContext context)
+        {
+            if (context.Request.Method != "GET")
+            {
+                var remoteIp = context.Connection.RemoteIpAddress;
+                _logger.LogDebug($"Request from Remote IP address: {remoteIp}");
+
+                string[] ip = _adminSafeList.Split(';');
+
+                var bytes = remoteIp.GetAddressBytes();
+                var badIp = true;
+                foreach (var address in ip)
+                {
+                    var testIp = IPAddress.Parse(address);
+                    if (testIp.GetAddressBytes().SequenceEqual(bytes))
+                    {
+                        badIp = false;
+                        break;
+                    }
+                }
+
+                if (badIp)
+                {
+                    _logger.LogInformation(
+                        $"Forbidden Request from Remote IP address: {remoteIp}");
+                    context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
+                    return;
+                }
+            }
+
+            await _next.Invoke(context);
+
+        }
+    }
+}

+ 28 - 0
MicroServices/DopInterfacePlatform/JWTExtensions.cs

@@ -0,0 +1,28 @@
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.IdentityModel.Tokens;
+using System.Text;
+
+namespace DopInterfacePlatform
+{
+    public static class JWTExtensions
+    {
+        public static AuthenticationBuilder AddJWTAuthentication(this IServiceCollection services, JwtOptions jwtOptions)
+        {
+            return services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+                .AddJwtBearer(x =>
+                {
+                    x.TokenValidationParameters = new()
+                    {
+                        ValidateIssuer = true,//是否验证发行商
+                        ValidateAudience = true,//是否验证受众者
+                        ValidateLifetime = true,//是否验证失效时间
+                        ValidateIssuerSigningKey = true,//是否验证签名键
+                        ValidIssuer = jwtOptions.Issuer,
+                        ValidAudience = jwtOptions.Audience,
+                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.Key))
+                    };
+                });
+        }
+    }
+}

+ 25 - 0
MicroServices/DopInterfacePlatform/JwtOptions.cs

@@ -0,0 +1,25 @@
+namespace DopInterfacePlatform
+{
+    public class JwtOptions
+    {
+        /// <summary>
+        /// 签发者
+        /// </summary>
+        public string Issuer { get; set; }
+
+        /// <summary>
+        /// 接收者
+        /// </summary>
+        public string Audience { get; set; }
+
+        /// <summary>
+        /// 密钥
+        /// </summary>
+        public string Key { get; set; }
+
+        /// <summary>
+        /// 过期时间
+        /// </summary>
+        public int ExpireSeconds { get; set; }
+    }
+}

+ 108 - 0
MicroServices/DopInterfacePlatform/LogFilter.cs

@@ -0,0 +1,108 @@
+using DopInterfacePlatform.Entity;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+using System.Diagnostics;
+
+namespace DopInterfacePlatform
+{
+    /// <summary>
+    /// 记录日志
+    /// </summary>
+    public class LogFilter : ActionFilterAttribute
+    {
+        // private IBusApiOperatorRepository api_operator_repository;
+
+        private Stopwatch stopwach { get; set; }
+        private string actionArguments { get; set; }
+        private Dictionary<string, object> keyValuePairs { set; get; }
+
+        private readonly DopInterfacePlatformContext _context;
+
+        public LogFilter(DopInterfacePlatformContext context)
+        {
+            _context = context;
+        }
+
+        public override void OnActionExecuting(ActionExecutingContext context)
+        {
+            base.OnActionExecuting(context);
+
+            //is not controller return
+            if (!(context.ActionDescriptor is ControllerActionDescriptor action))
+                return;
+            var request = context.HttpContext.Request;
+            //启动倒带方式
+            request.EnableBuffering();
+            if (request.Method.ToLower().Equals("post"))
+            {
+                request.Body.Position = 0;
+                using var requestReader = new StreamReader(request.Body);
+                var requestContent = requestReader.ReadToEnd();
+                request.Body.Position = 0;
+            }
+
+            stopwach = new Stopwatch();
+            stopwach.Start();
+            if(context.ActionArguments.Count>0)
+            {
+                actionArguments = context.ActionArguments.ToJsonString();
+            }
+            stopwach = new Stopwatch();
+            stopwach.Start();
+        }
+
+        public override void OnActionExecuted(ActionExecutedContext context)
+        {
+            base.OnActionExecuted(context);
+
+            //is not controller return
+            if (!(context.ActionDescriptor is ControllerActionDescriptor action))
+                return;
+
+            stopwach.Stop();
+            var time = stopwach.Elapsed;
+
+            // string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
+            string logMethod = context.HttpContext.Request.Method;
+            dynamic result = context.Result.GetType().Name == "EmptyResult"
+                ? new { Value = "无返回结果" }
+                : context.Result as dynamic;
+            string res = "在返回结果前发生了异常";
+            try
+            {
+                if (result != null)
+                {
+                    res = Newtonsoft.Json.JsonConvert.SerializeObject(result.Value);
+                }
+            }
+            catch (System.Exception ex)
+            {
+                res = "日志未获取到结果,返回的数据无法序列化!" + ex.Message;
+            }
+
+            //转换ActionDescriptor 
+            string logController = context.RouteData.Values["Controller"].ToString();
+            var logAction = context.RouteData.Values["Action"].ToString();
+            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
+            var ipAddress = context.HttpContext.Connection.RemoteIpAddress.ToString();
+            if(logAction!="GetToken")
+            {
+                var model = new InterfacePlatformLog();
+                if (actionArguments == null)
+                {
+                    actionArguments = "";
+                }
+                model.operatorcol_time = DateTime.Now;
+                model.operatorcol_ip = ipAddress;
+                model.operatorcol_duration = (int)time.TotalSeconds * 1000;
+                model.operatorcol_request = $"{logController}-{logAction}-{logMethod}-{actionArguments}"; //调用入参
+                model.operatorcol_respone = res; //调用出参 
+
+                _context.InterfacePlatformLog.Add(model);
+                _context.SaveChanges();
+            }
+        }
+    }
+}

+ 65 - 0
MicroServices/DopInterfacePlatform/Program.cs

@@ -0,0 +1,65 @@
+using DopInterfacePlatform.Interface;
+using DopInterfacePlatform.Service;
+using Microsoft.EntityFrameworkCore;
+using Swashbuckle.AspNetCore.SwaggerGen;
+using WebApiTest;
+
+namespace DopInterfacePlatform
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            var builder = WebApplication.CreateBuilder(args);
+
+            // Add services to the container.
+
+            builder.Services.AddControllers();
+            builder.Services.AddScoped<ClientIpCheckActionFilter>(container =>
+            {
+                var loggerFactory = container.GetRequiredService<ILoggerFactory>();
+                var logger = loggerFactory.CreateLogger<ClientIpCheckActionFilter>();
+
+                return new ClientIpCheckActionFilter(builder.Configuration["IpWhiteList"], logger);
+            });
+            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
+            builder.Services.AddEndpointsApiExplorer();
+            builder.Services.AddSwaggerGen();
+            builder.Services.AddScoped<IJwtService, JwtService>();
+            JwtOptions jwtOpt = builder.Configuration.GetSection("JWT").Get<JwtOptions>();
+            builder.Services.AddJWTAuthentication(jwtOpt);
+            builder.Services.Configure<SwaggerGenOptions>(c =>
+            {
+                c.AddAuthenticationHeader();
+            });
+
+            builder.Services.AddDbContext<DopInterfacePlatformContext>(opt =>
+               opt.UseSqlServer(builder.Configuration["ConnectionStrings:todoContext"]));
+
+
+            builder.Services.AddMvcCore(options =>
+            {
+                options.Filters.Add<LogFilter>();
+            }).AddApiExplorer();
+
+            var app = builder.Build();
+
+            // Configure the HTTP request pipeline.
+
+            app.UseSwagger();
+            app.UseSwaggerUI();
+
+
+            app.UseHttpsRedirection();
+
+            app.UseAuthentication();//注意,一定得先启动这个
+            app.UseAuthorization();
+
+            app.UseMiddleware<IpWhiteListMiddleware>(builder.Configuration["IpWhiteList"]);
+
+            app.MapControllers();
+
+            app.Run();
+        }
+    }
+}

+ 21 - 0
MicroServices/DopInterfacePlatform/Properties/PublishProfiles/FolderProfile.pubxml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <DeleteExistingFiles>true</DeleteExistingFiles>
+    <ExcludeApp_Data>false</ExcludeApp_Data>
+    <LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <PublishProvider>FileSystem</PublishProvider>
+    <PublishUrl>C:\Users\yuanhefei\Desktop\DOP文档\publish\DOPInterfacePlatform</PublishUrl>
+    <WebPublishMethod>FileSystem</WebPublishMethod>
+    <_TargetId>Folder</_TargetId>
+    <SiteUrlToLaunchAfterPublish />
+    <TargetFramework>net6.0</TargetFramework>
+    <ProjectGuid>58b598ba-29fc-492e-a976-d271f3a842c8</ProjectGuid>
+    <SelfContained>false</SelfContained>
+  </PropertyGroup>
+</Project>

+ 11 - 0
MicroServices/DopInterfacePlatform/Properties/PublishProfiles/FolderProfile.pubxml.user

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121.
+-->
+<Project>
+  <PropertyGroup>
+    <_PublishTargetUrl>C:\Users\yuanhefei\Desktop\DOP文档\publish\DOPInterfacePlatform</_PublishTargetUrl>
+    <History>True|2023-09-06T08:32:23.0343111Z;True|2023-09-06T16:29:00.3120067+08:00;True|2023-09-06T16:20:50.3191564+08:00;True|2023-09-06T16:16:12.2283892+08:00;True|2023-09-06T16:16:02.3726602+08:00;True|2023-09-06T16:12:46.4394558+08:00;True|2023-09-06T15:50:40.9163484+08:00;True|2023-09-06T15:15:21.6056173+08:00;</History>
+    <LastFailureDetails />
+  </PropertyGroup>
+</Project>

+ 31 - 0
MicroServices/DopInterfacePlatform/Properties/launchSettings.json

@@ -0,0 +1,31 @@
+{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:24100",
+      "sslPort": 44393
+    }
+  },
+  "profiles": {
+    "DopInterfacePlatform": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "applicationUrl": "http://localhost:9800;https://localhost:9801",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "launchUrl": "swagger",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}

+ 21 - 0
MicroServices/DopInterfacePlatform/Service/JwtService.cs

@@ -0,0 +1,21 @@
+using DopInterfacePlatform.Interface;
+using Microsoft.IdentityModel.Tokens;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+
+namespace DopInterfacePlatform.Service
+{
+    public class JwtService : IJwtService
+    {
+        public string BuildToken(IEnumerable<Claim> claims, JwtOptions options)
+        {
+            //过期时间
+            TimeSpan timeSpan = TimeSpan.FromSeconds(options.ExpireSeconds);//token过期时间
+            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(options.Key));//加密的token密钥
+            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);//签名证书,其值为securityKey和HmacSha256Signature算法
+            var tokenDescriptor = new JwtSecurityToken(options.Issuer, options.Audience, claims, expires: DateTime.Now.Add(timeSpan), signingCredentials: credentials);//表示jwt token的描述信息,其值包括Issuer签发方,Audience接收方,Claims载荷,过期时间和签名证书
+            return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);//使用该方法转换为字符串形式的jwt token返回
+        }
+    }
+}

+ 610 - 0
MicroServices/DopInterfacePlatform/StringHelper.cs

@@ -0,0 +1,610 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System.Collections;
+using System.Text;
+using System.Xml;
+
+namespace DopInterfacePlatform
+{
+    public static class StringHelper
+    {
+        private static int[] numbers = new[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+        /// <summary>
+        /// 随机字符串数组集合
+        /// </summary>
+        private static readonly string[] NonceStrings = new string[] { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+        /// <summary>
+        /// 四舍五入取整数部分
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static int StringToIntMathRound(this object @this)
+        {
+            string s_this = @this.ToString();
+            int i_result = 0;
+            if (s_this.Contains("."))
+            {
+                var tS =s_this.Split(".");
+                i_result = Convert.ToInt32(tS[0]);
+                if (Convert.ToInt32(tS[1].Substring(0, 1)) > 4)
+                {
+                    i_result += 1;
+                }
+            }
+            else
+            {
+                i_result = Convert.ToInt32(@this);
+            }
+
+            return i_result;
+        }
+        
+        /// <summary>
+        /// 生成指定长度的随机字符串
+        /// </summary>
+        /// <returns></returns>
+        public static string CreateNonceStr(this int stringLenght)
+        {
+            Random random = new Random();
+            var sb = new StringBuilder();
+            var length = NonceStrings.Length;
+            for (int i = 0; i < stringLenght; i++)
+            {
+                //通过random获得的随机索引到,NonceStrings数组中获取对应数组值
+                sb.Append(NonceStrings[random.Next(length - 1)]);
+            }
+            return sb.ToString();
+        }
+
+        
+        /// <summary>
+        /// 获取指定长度的随机数
+        /// </summary>
+        /// <returns></returns>
+        public static string GetRandom(this string @prexString, int lenght)
+        {
+            string result = prexString;
+            Random rd = new Random();
+            for (int i = 0; i < lenght - prexString.Length; i++)
+            {
+                int RandKey = rd.Next(100, 999);
+                var index = RandKey % 10;
+                result += numbers[index].ToString();
+            }
+            return result;
+        }
+
+
+        /// <summary>
+        /// decimal取指定位小数返回
+        /// </summary>
+        /// <param name="this"></param>
+        /// <param name="decimals"></param>
+        /// <returns></returns>
+        public static decimal DecimalsFormat(this decimal @this,int decimals=2)
+        {
+            return Math.Round(@this, decimals);
+        }
+
+        /// <summary>
+        /// 涉及到金额部分把最后的0 去掉
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static string CashFormat(this object @this)
+        {
+            string cashValue = @this.ToString();
+            if (cashValue != null && cashValue.Contains(".")) //
+            {
+                while (cashValue.EndsWith("0"))
+                {
+                    cashValue = cashValue.Substring(0, cashValue.Length - 1);
+                }
+
+                if (cashValue.EndsWith("."))
+                    cashValue = cashValue.Substring(0, cashValue.Length - 1);
+            }
+
+            return cashValue;
+        }
+
+        /// <summary>
+        /// 判断是否为空
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static bool IsNullOrWhiteSpace(this string @this)
+        {
+            if (@this == null) return true;
+            return string.IsNullOrWhiteSpace(@this.Trim()) || @this == "null";
+        }
+
+        /// <summary>
+        /// tostring的另一个版本,当是null字符串时返回空串
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static string ToSelfOrNullString(this string @this)
+        {
+            if (@this == null) return "";
+            return string.IsNullOrWhiteSpace(@this.Trim()) || @this == "null" ? "" : @this;
+        }
+
+        public static Hashtable GetProperties<T>(this T @userInfo)
+        {
+            Hashtable hashtable = new Hashtable();
+            foreach (System.Reflection.PropertyInfo p in userInfo.GetType().GetProperties())
+            {
+                hashtable.Add(p.Name, p.GetValue(userInfo));
+            }
+            return hashtable;
+        }
+        /// <summary>
+        /// 去掉Emoji表情
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static string RemoveEmoji(this string @this)
+        {
+            foreach (var strTmp in @this)
+            {
+                byte[] bts = Encoding.UTF32.GetBytes(strTmp.ToString());
+                
+                if (bts[0].ToString() == "253"&& bts[1].ToString() == "255")
+                {
+                    @this = @this.Replace(strTmp.ToString(), "");
+                }
+                    
+            }
+            return @this;
+        }
+
+
+        /// <summary>
+        /// 将Json字符串转换为对应的Json对象
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static T ToJsonObject<T>(this string @this)
+        {
+            return JsonConvert.DeserializeObject<T>(@this);
+        }
+        public static string DateTimeOfDayWeek(this string @this)
+        {
+            try
+            {
+
+                return ((int) Convert.ToDateTime(@this).DayOfWeek).ToString();
+            }
+            catch (Exception e)
+            {
+                return "";
+            }
+        }
+
+        public static string YuanToFen(this string money)
+        {
+            return Convert.ToInt64(Convert.ToDecimal(money) * 100).ToString();
+        } 
+        
+        public static string FenToYuan(this int money)
+        {
+            return (Convert.ToDecimal(money)/100).ToString();
+        }
+        /// <summary>
+        /// 将对象转换为string字符串
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static string ToJsonString(this object @this)
+        {
+            return JsonConvert.SerializeObject(@this);
+        }
+
+        /// <summary>
+        /// 排序字段
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static Dictionary<string, object> SortDictionary(this Dictionary<string, object> @this)
+        {
+            Dictionary<string, object> keyValues = new Dictionary<string, object>();
+            foreach (var item in @this)
+            {
+                if (item.Value == null || item.Value.ToString() == "")
+                {
+                    continue;
+                }
+                if(item.Key== "PatType")
+                {
+
+                }
+                if (item.Value.GetType().Name == "JObject")
+                {
+                    JObject j_object = item.Value as JObject;
+                    keyValues = keyValues.Concat(j_object.JObjectToDictionary()).ToDictionary(k => k.Key, v => v.Value);
+                }
+                else
+                {
+                    keyValues.Add(item.Key, item.Value);
+                }
+            }
+            return keyValues.OrderBy(p => p.Key).Where(d => d.Value != null).ToDictionary(p => p.Key, o => o.Value);
+        }
+
+        /// <summary>
+        /// JObject to Dictionary<string, object>
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        private static Dictionary<string, object> JObjectToDictionary(this JObject @this)
+        {
+            Dictionary<string, object> keyValues = new Dictionary<string, object>();
+            foreach (var item in @this)
+            {
+                keyValues.Add(item.Key, item.Value);
+
+                //不考虑有多层的情况
+                //if (item.Value.GetType().Name == "JObject")
+                //{
+                //    JObject j_object = item.Value as JObject;
+                //    //还有子项目
+                //    keyValues = keyValues.Concat(j_object.JObjectToDictionary()).ToDictionary(k => k.Key, v => v.Value);
+                //}
+                //else
+                //{
+                //    keyValues.Add(item.Key, item.Value);
+                //}
+            }
+            return keyValues;
+        }
+
+        /// <summary>
+        /// 转换成签名串
+        /// </summary>
+        /// <param name="this"></param>
+        /// <returns></returns>
+        public static string ToSignString(this object @this)
+        {
+            var objName = @this.GetType().Name;
+            if (objName == "DateTime")
+            {
+                return Convert.ToDateTime(@this).ToString("yyyy-MM-dd HH:mm:ss");
+            }
+            else
+            {
+                return @this.ToString();
+            }
+        }
+
+        /// <summary>
+        /// BASE64编码
+        /// </summary>
+        /// <param name="un_code_string"></param>
+        /// <param name="code_type"></param>
+        /// <returns></returns>
+        public static string EncodeBase64(this string un_code_string,string code_type= "utf-8")
+        {
+            byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(un_code_string);
+            string encode;
+            try
+            {
+                encode = Convert.ToBase64String(bytes);
+            }
+            catch
+            {
+                encode = un_code_string;
+            }
+            return encode;
+        }
+        /// <summary>
+        /// BASE64解码
+        /// </summary>
+        /// <param name="code_string"></param>
+        /// <param name="code_type"></param>
+        /// <returns></returns>
+        public static string DecodeBase64(this string code_string,string code_type = "utf-8")
+        {
+            byte[] bytes = Convert.FromBase64String(code_string);
+            string decode;
+            try
+            {
+                decode = Encoding.GetEncoding(code_type).GetString(bytes);
+            }
+            catch
+            {
+                decode = code_string;
+            }
+            return decode;
+        }
+
+
+        /// <summary>
+        /// xml格式的字符串转换成对象
+        /// </summary>
+        /// <param name="xmlStr"></param>
+        /// <returns></returns>
+        public static T XmlToObject<T>(this string xmlStr) where T : new()
+        {
+            try
+            {
+                T obj = new T();
+                var repType = typeof(T);
+                XmlDocument document = new XmlDocument();
+                document.LoadXml(xmlStr);    //加载Xml文件  
+                XmlElement node = document.DocumentElement; //xml的根标签
+                var properties = repType.GetProperties();
+                foreach (var itemProp in properties)
+                {
+                    #region current type is List
+                    if (itemProp.PropertyType.FullName.Contains("System.Collections.Generic.List"))
+                    {
+                        object array = new object();
+                        var arryLength = 0;
+                        var notNullLength = 0;
+                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
+
+                        var objList = itemProp.GetValue(obj, null) as System.Collections.IEnumerable;
+                        var enumt = objList.GetEnumerator();
+                        //enumt.
+                        var currentType = itemProp.PropertyType.GetGenericArguments()[0];
+
+                        foreach (XmlNode xmlitem in node.ChildNodes)
+                        {
+                            if (xmlitem.Name == itemProp.Name)
+                            {
+                                arryLength++;
+                            }
+                        }
+                        if (arryLength > 0)
+                        {
+                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
+                            foreach (XmlNode item in node.ChildNodes)
+                            {
+                                //current type is array
+                                if (item.Name == itemProp.Name)
+                                {
+                                    var model = currentType.Assembly.CreateInstance(currentType.FullName); // arryType.GetElementType().Assembly.CreateInstance(currentType.FullName);
+                                    SetArray(item.ChildNodes, model, true);
+                                    arrayModel.Add(model);
+                                    //arrayModel[notNullLength] = model;
+                                    notNullLength++;
+                                }
+                            }
+                            itemProp.SetValue(obj, arrayModel, null);
+                        }
+
+                        continue;
+                    }
+                    #endregion
+                    var baseType = itemProp.PropertyType.BaseType.Name;
+                    if (baseType == "Array")
+                    {
+                        #region Current type is Array
+                        object array = new object();
+                        var arryLength = 0;
+                        var notNullLength = 0;
+                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
+
+                        foreach (XmlNode xmlitem in node.ChildNodes)
+                        {
+                            if (xmlitem.Name == itemProp.Name && xmlitem.ChildNodes!=null && xmlitem.ChildNodes.Count>0)
+                            {
+                                arryLength++;
+                            }
+                        }
+                        if (arryLength > 0)
+                        {
+                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
+                            foreach (XmlNode item in node.ChildNodes)
+                            {
+                                //current type is array
+                                if (item.Name == itemProp.Name && item.ChildNodes!=null && item.ChildNodes.Count>0)
+                                {
+                                    var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
+                                    SetArray(item.ChildNodes, model);
+                                    arrayModel[notNullLength] = model;
+                                    notNullLength++;
+                                }
+                            }
+                            itemProp.SetValue(obj, arrayModel, null);
+                        }
+                        #endregion
+                    }
+                    else
+                    {
+                        #region Current type isn't Array
+                        foreach (XmlNode item in node.ChildNodes)
+                        {
+                            #region Current type is Number
+                            if (itemProp.Name == item.Name && (itemProp.PropertyType == typeof(long) || itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(string)))
+                            {
+                                if (itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(long))
+                                {
+                                    if (!string.IsNullOrEmpty(item.InnerText))
+                                    {
+                                        if (itemProp.PropertyType == typeof(int))
+                                        {
+                                            itemProp.SetValue(obj, Convert.ToInt32(item.InnerText), null);
+                                        }
+                                        else
+                                        {
+                                            itemProp.SetValue(obj, Convert.ToInt64(item.InnerText), null);
+                                        }
+
+                                    }
+                                    else
+                                    {
+                                        itemProp.SetValue(obj, 0, null);
+                                    }
+                                }
+                                else
+                                {
+                                    itemProp.SetValue(obj, item.InnerText, null);
+                                }
+                            }
+                            #endregion
+
+                            #region Current type is Model
+                            if (itemProp.PropertyType != typeof(long) && itemProp.PropertyType != typeof(string) && itemProp.PropertyType != typeof(int) && itemProp.PropertyType.Name == item.Name && item.HasChildNodes && item.FirstChild.NodeType == System.Xml.XmlNodeType.Element)
+                            {
+                                var modelType = itemProp.PropertyType.UnderlyingSystemType;
+                                var model = modelType.Assembly.CreateInstance(modelType.FullName);
+                                SetArray(item.ChildNodes, model);
+                                itemProp.SetValue(obj, model, null);
+                            }
+                            #endregion
+                        }
+                        #endregion
+
+                    }
+                }
+                repType = obj.GetType();
+                return obj;
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+
+        #region Set array value
+        private static Object SetArray(XmlNodeList xmlNodeList, object obj, bool isList = false)
+        {
+            try
+            {
+                var type = obj.GetType();
+                var properties = type.GetProperties();
+                foreach (var itemProp in properties)
+                {
+                    //if (isList)
+                    if (itemProp.PropertyType.FullName.Contains("System.Collections.Generic.List"))
+                    {
+                        #region Current type is List
+                        object array = new object();
+                        var arryLength = 0;
+                        var notNullLength = 0;
+                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
+                        var currentType = itemProp.PropertyType.GetGenericArguments()[0];
+                        foreach (XmlNode xmlitem in xmlNodeList)
+                        {
+                            if (xmlitem.Name == itemProp.Name)
+                            {
+                                arryLength++;
+                            }
+                        }
+
+                        if (arryLength > 0)
+                        {
+                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
+                            foreach (XmlNode item in xmlNodeList)
+                            {
+                                //current type is array
+                                if (item.Name == itemProp.Name)
+                                {
+                                    var model = currentType.Assembly.CreateInstance(currentType.FullName); // var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
+                                    SetArray(item.ChildNodes, model, true);
+                                    arrayModel.Add(model);
+                                    notNullLength++;
+
+                                }
+                            }
+                            itemProp.SetValue(obj, arrayModel, null);
+                        }
+                        #endregion
+                        return obj;
+                    }
+
+
+                    var baseType = itemProp.PropertyType.BaseType.Name;
+                    if (baseType == "Array")
+                    {
+                        #region Current type is Array
+                        object array = new object();
+                        var arryLength = 0;
+                        var notNullLength = 0;
+                        var arryType = itemProp.PropertyType.UnderlyingSystemType;
+                        foreach (XmlNode xmlitem in xmlNodeList)
+                        {
+                            if (xmlitem.Name == itemProp.Name)
+                            {
+                                arryLength++;
+                            }
+                        }
+
+                        if (arryLength > 0)
+                        {
+                            var arrayModel = arryType.InvokeMember("Set", System.Reflection.BindingFlags.CreateInstance, null, array, new object[] { arryLength }) as System.Collections.IList;
+                            foreach (XmlNode item in xmlNodeList)
+                            {
+                                //current type is array
+                                if (item.Name == itemProp.Name)
+                                {
+                                    var model = arryType.GetElementType().Assembly.CreateInstance(arryType.GetElementType().FullName);
+                                    SetArray(item.ChildNodes, model);
+                                    arrayModel[notNullLength] = model;
+                                    notNullLength++;
+
+                                }
+                            }
+                            itemProp.SetValue(obj, arrayModel, null);
+                        }
+                        #endregion
+                    }
+                    else
+                    {
+                        foreach (XmlNode item in xmlNodeList)
+                        {
+                            #region Current type is Number
+                            if (itemProp.Name == item.Name && (itemProp.PropertyType == typeof(long) || itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(string)))
+                            {
+                                if (itemProp.PropertyType == typeof(int) || itemProp.PropertyType == typeof(long))
+                                {
+                                    if (!string.IsNullOrEmpty(item.InnerText))
+                                    {
+                                        if (itemProp.PropertyType == typeof(int))
+                                        {
+                                            itemProp.SetValue(obj, Convert.ToInt32(item.InnerText), null);
+                                        }
+                                        else
+                                        {
+                                            itemProp.SetValue(obj, Convert.ToInt64(item.InnerText), null);
+                                        }
+                                    }
+                                    else
+                                    {
+                                        itemProp.SetValue(obj, 0, null);
+                                    }
+                                }
+                                else
+                                {
+                                    itemProp.SetValue(obj, item.InnerText, null);
+                                }
+                            }
+                            #endregion
+
+                            #region Current type is Model
+                            if (itemProp.PropertyType != typeof(long) && itemProp.PropertyType != typeof(int) && itemProp.PropertyType != typeof(string) && itemProp.PropertyType.Name == item.Name && item.HasChildNodes && item.FirstChild.NodeType == System.Xml.XmlNodeType.Element)
+                            {
+                                var modelType = itemProp.PropertyType.UnderlyingSystemType;
+                                var model = modelType.Assembly.CreateInstance(modelType.FullName);
+                                SetArray(item.ChildNodes, model);
+                                itemProp.SetValue(obj, model, null);
+                            }
+                            #endregion
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                throw new Exception(ex.Message);
+            }
+            return obj;
+        }
+        #endregion
+    }
+}

+ 44 - 0
MicroServices/DopInterfacePlatform/SwaggerGenOptionsExtensions.cs

@@ -0,0 +1,44 @@
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace DopInterfacePlatform
+{
+    public static class SwaggerGenOptionsExtensions
+    {
+        /// <summary>
+        /// 为swagger增加Authentication报文头
+        /// </summary>
+        /// <param name="option"></param>
+        public static void AddAuthenticationHeader(this SwaggerGenOptions option)
+        {
+            option.AddSecurityDefinition("Authorization",
+                new OpenApiSecurityScheme
+                {
+                    Description = "Authorization header. \r\nExample:Bearer 12345ABCDE",
+                    Name = "Authorization",
+                    In = ParameterLocation.Header,
+                    Type = SecuritySchemeType.ApiKey,
+                    Scheme = "Authorization"
+                }
+                ); ;
+
+            option.AddSecurityRequirement(new OpenApiSecurityRequirement()
+            {
+                {
+                    new OpenApiSecurityScheme
+                    {
+                        Reference=new OpenApiReference
+                        {
+                            Type=ReferenceType.SecurityScheme,
+                            Id="Authorization"
+                        },
+                        Scheme="oauth2",
+                        Name="Authorization",
+                        In=ParameterLocation.Header,
+                    },
+                    new List<string>()
+                }
+            });
+        }
+    }
+}

+ 13 - 0
MicroServices/DopInterfacePlatform/WeatherForecast.cs

@@ -0,0 +1,13 @@
+namespace DopInterfacePlatform
+{
+    public class WeatherForecast
+    {
+        public DateTime Date { get; set; }
+
+        public int TemperatureC { get; set; }
+
+        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+        public string? Summary { get; set; }
+    }
+}

+ 8 - 0
MicroServices/DopInterfacePlatform/appsettings.Development.json

@@ -0,0 +1,8 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  }
+}

+ 19 - 0
MicroServices/DopInterfacePlatform/appsettings.json

@@ -0,0 +1,19 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  "JWT": {
+    "Issuer": "zzy2025@qq.com",
+    "Audience": "zzy2025@qq.com",
+    "Key": "A86DA1301B954748B3B21B6AA9F2F743", //加密密钥
+    "ExpireSeconds": 600 //密钥过期时间
+  },
+  "IpWhiteList": "172.16.8.154;127.0.0.1;192.168.1.5;::1",
+  "ConnectionStrings": {
+    "todoContext": "Server=172.16.8.154;Database=DopInterfacePlatform;uid=sa;pwd=ac%qams)aCXI;Trusted_Connection=false;TrustServerCertificate=True"
+  }
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov