| Quintiq file version 2.0 | 
| #parent: #root | 
| StaticMethod RefreshOfflinePlan ( | 
|   MacroPlan macroPlan | 
| ) | 
| { | 
|   TextBody: | 
|   [* | 
|     macroPlan.NewOfflinePlanTable( relflush ); | 
|      | 
|     nopt         := macroPlan.NewOfflinePlanTable( relnew, SaveDateTime := DateTime::ActualTime() ); | 
|      | 
|     // 计划开始时间 | 
|     planningDate := macroPlan.StartOfPlanning().Date()  | 
|      | 
|     // 初始化下线计划列 | 
|     traverse ( macroPlan, Period_MP, pmp, pmp.IsPlanning() and not pmp.IsHistorical() ) { | 
|       nopt.NewOfflinePlanColumn( relnew, StartDate := pmp.StartDate(), EndDate := pmp.EndDate() ); | 
|     } | 
|      | 
|     // 生成下线计划表【一条产线在同一天不会产生两次相同产品的周期任务】 | 
|     traverse ( macroPlan, Unit, u, u.HasCapacityTypeTime()  | 
|     //           and u.Name() = "eMotor Assy (France)" // 测试本地场景时可以过滤 | 
|     //           and u.Name() = "DL-MoMo"              // 测试实际场景时可以过滤 | 
|               )  | 
|     { | 
|       // 循环遍历周期任务的NewSupply【生成明细下线计划】 | 
|       traverse ( u, Operation, o ) { | 
|         traverse ( o, PeriodTaskOperation.NewSupply, ns ) { | 
|           // ProductInStockingPoint_MP | 
|           pisp     := ns.AsProductionSupply().ProductInStockingPoint_MP(); | 
|           // ProductInStockingPointInPeriodPlanningLeaf | 
|           pispippl := ns.ProductInStockingPointInPeriodPlanningLeaf(); | 
|           // Period_MP | 
|           pmp      := pispippl.Period_MP(); | 
|           // ShiftPattern | 
|           sp       := ns.PeriodTask_MP().UnitPeriod().astype( UnitPeriodTimeBase ).ShiftPattern(); | 
|           // ShiftDayTime | 
|           sdt      := select( sp, ShiftDayTime, tempSDT, tempSDT.Name() = tempSDT.ShiftPattern().Name() ); | 
|            | 
|           // 生成下线计划【产线明细】行 | 
|           detailedNOPR   := select( nopt, NewOfflinePlanRow, tempNOPR, tempNOPR.ProductionLine() = u.ID() and tempNOPR.ProductID() = pisp.ProductID() and tempNOPR.StockingPointID() = pisp.StockingPointID() and tempNOPR.Type() = "1" ); | 
|           if ( isnull( detailedNOPR ) ) { | 
|             detailedNOPR := nopt.NewOfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := pisp.ProductID(),StockingPointID := pisp.StockingPointID(), Type := "1", OperationID := o.ID() ); | 
|           } | 
|            | 
|           // 生成下线计划列 | 
|           nopc   := select( nopt, NewOfflinePlanColumn, tempNOPC, tempNOPC.StartDate() = pmp.StartDate() and tempNOPC.EndDate() = pmp.EndDate() ); | 
|           if ( isnull( nopc ) ) { | 
|             nopc := nopt.NewOfflinePlanColumn( relnew, StartDate := pmp.StartDate(), EndDate := pmp.EndDate() ); | 
|           } | 
|            | 
|           // 生成下线计划【产线明细】单元格 | 
|           detaileNOPCell := select( detailedNOPR, NewOfflinePlanCell, tempNOPCell, tempNOPCell.NewOfflinePlanColumn() = nopc ); | 
|           if ( isnull ( detaileNOPCell ) ) { | 
|             detaileNOPCell := detailedNOPR.NewOfflinePlanCell( relnew,  | 
|                                                                Quantity          := ns.Quantity().Round( 0 ),  | 
|                                                                InventoryWeight   := pispippl.InventoryLevelEnd() - pispippl.MinInventoryLevel(), | 
|                                                                ShiftPatternName  := guard( sp.Name(), "" ), | 
|                                                                ShiftPatternStart := guard( sdt.StartDateTime().Format( "H:m" ), "" ), | 
|                                                                ShiftPatternEnd   := guard( sdt.EndDateTIme().Format( "H:m" ), "" ) ); | 
|             detaileNOPCell.NewOfflinePlanColumn( relset, nopc ); | 
|           } | 
|         } | 
|       } | 
|        | 
|       // 补齐空格子 | 
|       traverse ( nopt, NewOfflinePlanRow, nopr ) { | 
|         traverse ( nopt, NewOfflinePlanColumn, nopc ) { | 
|           cell   := select( nopr, NewOfflinePlanCell, tempNOPCell, tempNOPCell.NewOfflinePlanColumn() = nopc ); | 
|           if ( isnull( cell ) ) { | 
|             uptb := select( macroPlan, Unit.UnitPeriod.astype( UnitPeriodTimeBase ), tempUPTB,  | 
|                             tempUPTB.UnitID() = nopr.ProductionLine() and tempUPTB.StartDate() = nopc.StartDate() and tempUPTB.End().Date() = nopc.EndDate() ); | 
|             // ShiftPattern | 
|             sp   := uptb.ShiftPattern(); | 
|             // ShiftDayTime | 
|             sdt  := select( sp, ShiftDayTime, tempSDT, tempSDT.Name() = tempSDT.ShiftPattern().Name() ); | 
|             cell := nopr.NewOfflinePlanCell( relnew,  | 
|                                              ShiftPatternName  := guard( sp.Name(), "" ),  | 
|                                              ShiftPatternStart := guard( sdt.StartDateTime().Format( "H:m" ), "" ), | 
|                                              ShiftPatternEnd   := guard( sdt.EndDateTIme().Format( "H:m" ), "" ) ); | 
|             cell.NewOfflinePlanColumn( relset, nopc ); | 
|           } | 
|         } | 
|       } | 
|        | 
|       // 【生成合计下线计划】 | 
|       totalNOPR   := nopt.NewOfflinePlanRow( relnew, ProductID := "All", ProductionLine := u.ID(), Type := "2" ); | 
|       detailNOPRs := selectset( nopt, NewOfflinePlanRow, tempNOPR, tempNOPR.ProductionLine() = u.ID() and tempNOPR.Type() = "1" ); | 
|       traverse ( detailNOPRs, Elements, detailNOPR ) { | 
|         traverse ( detailNOPR, NewOfflinePlanCell, detailNOPCell ) { | 
|           // 生产下线计划【产线合计】单元格 | 
|           totalNOPRCell   := select( totalNOPR, NewOfflinePlanCell, tempNOPCell, tempNOPCell.NewOfflinePlanColumn() = detailNOPCell.NewOfflinePlanColumn() ); | 
|           if ( isnull( totalNOPRCell ) ) { | 
|             totalNOPRCell := totalNOPR.NewOfflinePlanCell( relnew,  | 
|                                                            ShiftPatternName  := detailNOPCell.ShiftPatternName(), | 
|                                                            ShiftPatternStart := detailNOPCell.ShiftPatternStart(), | 
|                                                            ShiftPatternEnd   := detailNOPCell.ShiftPatternEnd() ); | 
|             totalNOPRCell.NewOfflinePlanColumn( relset, detailNOPCell.NewOfflinePlanColumn() ); // 设置列 | 
|             // 将明细单元格关联到合计单元格 | 
|             totalNOPRCell.Detailed( relinsert, detailNOPCell ); | 
|           } else { | 
|             // 将明细单元格关联到合计单元格 | 
|             totalNOPRCell.Detailed( relinsert, detailNOPCell ); | 
|           } | 
|         } | 
|       } | 
|        | 
|       // 设置生产顺序【对下线计划明细生效】 | 
|       indexColumn    := select( nopt, NewOfflinePlanColumn, tempNOPC, tempNOPC.StartDate() = planningDate ); | 
|       previousColumn := indexColumn.PreviousNOPColumn(); | 
|       nextColumn     := indexColumn.NextNOPColumn(); | 
|       while ( not isnull( indexColumn.NextNOPColumn() ) | 
|     //          and indexColumn.ColumnDate() <= Date::Construct( 2020, 4, 1 ) // 测试实际场景时可以过滤 | 
|              )  | 
|       { | 
|         orderNr     := 1; | 
|         nopcells    := selectsortedset( indexColumn, NewOfflinePlanCell, tempNOPCell, tempNOPCell.FindProductionLineAndType( u.ID(), "1" ), tempNOPCell.InventoryWeight() ); | 
|         initialSize := nopcells.Size(); | 
|     //    info( "计划开始时间:", planningDate.Format( "Y-M2-D2" ), "    索引时间:", indexColumn.StartDate().Format( "Y-M2-D2" ), "    个数:", nopcells.Size() ); | 
|          | 
|         if ( nopcells.Size() > 0 ) { | 
|          | 
|           // 判定1 | 
|           previousOPCell := maxselect( previousColumn, NewOfflinePlanCell, tempNOPCell, tempNOPCell.FindProductionLineAndType( u.ID(), "1" ), tempNOPCell.OrderNr() ); | 
|           if ( isnull( previousOPCell ) or indexColumn.StartDate() = planningDate ) { | 
|             nopcell := nopcells.Element( 0 ); | 
|             nopcell.Order( "#" + orderNr.Format( "N(LPad0(2))" ) ); | 
|             nopcell.OrderNr( orderNr ); | 
|             orderNr++; | 
|             nopcells.Remove( nopcell ); | 
|           } else { | 
|             nopcell := select( nopcells, Elements, tempNOPCell, tempNOPCell.NewOfflinePlanRow().ProductID() =  previousOPCell.NewOfflinePlanRow().ProductID() ); | 
|             if ( not isnull( nopcell ) ) { | 
|               nopcell.Order( "#" + orderNr.Format( "N(LPad0(2))" ) ); | 
|               nopcell.OrderNr( orderNr ); | 
|               orderNr++; | 
|               nopcells.Remove( nopcell ); | 
|             } | 
|           } | 
|            | 
|           // 判定2 | 
|           nextNOPCells := selectset( nopcells, Elements, tempOPC, | 
|                                      exists( nextColumn, NewOfflinePlanCell, nextOPCell, nextOPCell.FindProductionLineAndType( u.ID(), "1" ) and  | 
|                                              nextOPCell.NewOfflinePlanRow().ProductID() = tempOPC.NewOfflinePlanRow().ProductID() ) ); // 找下一列是否有当前列生产的产品 | 
|           if ( nextNOPCells.Size() = 1 ) { | 
|             nopcell := nextNOPCells.Element( 0 ); | 
|             nopcell.Order( "#" + initialSize.Format( "N(LPad0(2))" ) ); | 
|             nopcell.OrderNr( initialSize ); | 
|             nopcells.Remove( nopcell ); | 
|           } | 
|            | 
|           // 判定3 | 
|           traverse ( nopcells, Elements, opcell ) { | 
|             opcell.Order( "#" + orderNr.Format( "N(LPad0(2))" ) ); | 
|             opcell.OrderNr( orderNr ); | 
|             orderNr++; | 
|             nopcells.Remove( opcell ); | 
|           } | 
|         } | 
|          | 
|         indexColumn    := indexColumn.NextNOPColumn(); | 
|         previousColumn := indexColumn.PreviousNOPColumn(); | 
|         nextColumn     := indexColumn.NextNOPColumn(); | 
|       } | 
|     } | 
|   *] | 
| } |