| Quintiq file version 2.0 | 
| #parent: #root | 
| StaticMethod RefreshOfflinePlan ( | 
|   MacroPlan macroPlan | 
| ) | 
| { | 
|   TextBody: | 
|   [* | 
|     macroPlan.OfflinePlanTable( relflush ); | 
|      | 
|     opt := macroPlan.OfflinePlanTable( relnew, SaveDateTime := DateTime::ActualTime() ); | 
|      | 
|     // 生成下线计划表 | 
|     traverse ( macroPlan, Unit, u, u.HasCapacityTypeTime() /*and u.Name() = "Body in White Line 1"*/ ) { | 
|       // 创建产线行 | 
|       opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "", Type := "0" ); | 
|        | 
|       traverse ( u, Operation, o ) { | 
|         traverse ( o, PeriodTaskOperation.NewSupply, ns ) { | 
|           // 找行 | 
|           oprQuantity := select( opt, OfflinePlanRow, tempOPR, tempOPR.ProductionLine() = u.ID() and tempOPR.ProductID() = ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID() and tempOPR.Type() = "1" ); | 
|           oprOrder    := select( opt, OfflinePlanRow, tempOPR, tempOPR.ProductionLine() = u.ID() and tempOPR.ProductID() = ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID() and tempOPR.Type() = "2" ); | 
|           if ( isnull( oprQuantity ) and isnull( oprOrder ) ) { | 
|             oprQuantity := opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID(), Type := "1", Notes := ns.AsProductionSupply().ProductInStockingPoint_MP().Product_MP().Notes() ); | 
|             oprOrder    := opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := ns.AsProductionSupply().ProductInStockingPoint_MP().ProductID(), Type := "2" ); | 
|           } | 
|            | 
|           // 找列 | 
|           opc := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = ns.Start().Date() ); | 
|           if ( isnull( opc ) ) { | 
|             opc := opt.OfflinePlanColumn( relnew, ColumnDate := ns.Start().Date() ); | 
|           } | 
|            | 
|           // 赋值单元格 | 
|           cellQuantity := opc.OfflinePlanCell( relnew, Value := [String]ns.Quantity().Round( 0 ), Shift := ns.PeriodTask_MP().UnitPeriod().astype( UnitPeriodTimeBase ).ShiftPattern().Name(), Quantity := ns.Quantity() ); | 
|           cellQuantity.OfflinePlanRow( relset, oprQuantity ); | 
|           cellOrder := opc.OfflinePlanCell( relnew, Value := "单号" + [String]ns.Quantity().Round( 0 ) + "_" + [String]( ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() ),  | 
|                                             Quantity := ns.Quantity(),  | 
|                                             InventoryWeight := ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() ); | 
|           cellOrder.OfflinePlanRow( relset, oprOrder ); | 
|         } | 
|       } | 
|        | 
|       // 创建总量行 | 
|       opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "3" ); | 
|       // 创建班次行 | 
|       opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "4" ); | 
|       // 创建班次开始时间行 | 
|       opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "5" ); | 
|       // 创建班次结束时间行 | 
|       opt.OfflinePlanRow( relnew, ProductionLine := u.ID(), ProductID := "Z", Type := "6" ); | 
|     } | 
|      | 
|     // 创建产品列&类型列 | 
|     productOPC := opt.OfflinePlanColumn( relnew, ColumnDate := macroPlan.StartOfPlanning().Date() - 2 ); | 
|     typeOPC    := opt.OfflinePlanColumn( relnew, ColumnDate := macroPlan.StartOfPlanning().Date() - 1 ); | 
|     traverse ( opt, OfflinePlanRow, opr ) { | 
|       if ( opr.Type() = "0" ) { | 
|         productLineCell := productOPC.OfflinePlanCell( relnew, Value := opr.ProductionLine() ); | 
|         productLineCell.OfflinePlanRow( relset, opr ); | 
|       } else if( opr.Type() = "1" ) { | 
|         productCell := productOPC.OfflinePlanCell( relnew, Value := opr.ProductID() + ifexpr( opr.Notes() = "", "", "-" + opr.Notes() ) ); | 
|         productCell.OfflinePlanRow( relset, opr ); | 
|         typeCell    := typeOPC.OfflinePlanCell( relnew, Value :=  "Quantity" ); | 
|         typeCell.OfflinePlanRow( relset, opr ); | 
|       } else if ( opr.Type() = "2" ) { | 
|         typeCell    := typeOPC.OfflinePlanCell( relnew, Value :=  "Order" ); | 
|         typeCell.OfflinePlanRow( relset, opr ); | 
|       } else if ( opr.Type() = "3" ) { | 
|         totalCell := productOPC.OfflinePlanCell( relnew, Value := "合计" ); | 
|         totalCell.OfflinePlanRow( relset, opr ); | 
|         totalCell := typeOPC.OfflinePlanCell( relnew, Value :=  "总量" ); | 
|         totalCell.OfflinePlanRow( relset, opr ); | 
|       } else if ( opr.Type() = "4" ) { | 
|         shiftCell := typeOPC.OfflinePlanCell( relnew, Value :=  "班次" ); | 
|         shiftCell.OfflinePlanRow( relset, opr ); | 
|       } else if ( opr.Type() = "5" ) { | 
|         shiftStartDateCell := typeOPC.OfflinePlanCell( relnew, Value :=  "班次开始时间" ); | 
|         shiftStartDateCell.OfflinePlanRow( relset, opr ); | 
|       } else if ( opr.Type() = "6" ) { | 
|         shiftEndDateCell := typeOPC.OfflinePlanCell( relnew, Value :=  "班次结束时间" ); | 
|         shiftEndDateCell.OfflinePlanRow( relset, opr ); | 
|       } | 
|     } | 
|      | 
|     // 补全总量&班次&班次开始时间&班次结束时间 | 
|     totalOPRs          := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "3" ); | 
|     shiftOPRs          := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "4" ); | 
|     shiftStartDateOPRs := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "5" ); | 
|     shiftEndDateOPRs   := selectset( opt, OfflinePlanRow, tempOPR, tempOPR.Type() = "6" ); | 
|     traverse ( opt, OfflinePlanColumn, opc, opc.OfflinePlanCell( relsize ) > 0 and opc.ColumnDate() >= macroPlan.StartOfPlanning().Date() ) { | 
|       traverse ( totalOPRs, Elements, totalOPR ) { | 
|         total     := sum( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = totalOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1", [Real]tempOPC.Value() ); | 
|         totalCell := opc.OfflinePlanCell( relnew, Value := [String]total ); | 
|         totalCell.OfflinePlanRow( relset, totalOPR ); | 
|       } | 
|        | 
|       traverse ( shiftOPRs, Elements, shiftOPR ) { | 
|         shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = shiftOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" );  | 
|         if ( not isnull( shift ) ) { | 
|           shiftCell := opc.OfflinePlanCell( relnew, Value := shift.Shift() ); | 
|           shiftCell.OfflinePlanRow( relset, shiftOPR ); | 
|         } | 
|       } | 
|        | 
|       traverse ( shiftStartDateOPRs, Elements, ssdOPR ) { | 
|         shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = ssdOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" );  | 
|         if ( not isnull( shift ) ) { | 
|           startDate     := guard( minselect( macroPlan, ShiftPattern.ShiftDayTime, tempSDT, tempSDT.ShiftPattern().Name() = shift.Shift(), tempSDT.Sequence() ).StartDateTime().Format( "H:m" ), "" ); | 
|           startDateCell := opc.OfflinePlanCell( relnew, Value := startDate ); | 
|           startDateCell.OfflinePlanRow( relset, ssdOPR ); | 
|         } | 
|       } | 
|        | 
|       traverse ( shiftEndDateOPRs, Elements, sedOPR ) { | 
|         shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = sedOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" );  | 
|         if ( not isnull( shift ) ) { | 
|           endDate     := guard( maxselect( macroPlan, ShiftPattern.ShiftDayTime, tempSDT, tempSDT.ShiftPattern().Name() = shift.Shift(), tempSDT.Sequence() ).EndDateTIme().Format( "H:m" ), "" ); | 
|           endDateCell := opc.OfflinePlanCell( relnew, Value := endDate ); | 
|           endDateCell.OfflinePlanRow( relset, sedOPR ); | 
|         } | 
|       } | 
|     } | 
|      | 
|     // 补全时间列 | 
|     indexDate := macroPlan.StartOfPlanning().Date(); | 
|     endDate   := Date::Construct( indexDate.Year(), 12, 31 ); | 
|     while ( indexDate <= endDate ) { | 
|       opc := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = indexDate ); | 
|       if ( isnull( opc ) ) { | 
|         opc := opt.OfflinePlanColumn( relnew, ColumnDate := indexDate ); | 
|       } | 
|       indexDate := indexDate + 1; | 
|     } | 
|      | 
|     Transaction::Transaction().PropagateAll(); | 
|      | 
|     // 设置生产顺序 | 
|     productionLines := selectuniquevalues( opt, OfflinePlanRow, tempOPR, true, tempOPR.ProductionLine() ); | 
|     traverse ( productionLines, Elements, pl ) { | 
|       indexColumn    := select( opt, OfflinePlanColumn, tempOPC, tempOPC.ColumnDate() = macroPlan.StartOfPlanning().Date() ); | 
|       previousColumn := indexColumn.PreviousColumn(); | 
|       nextColumn     := indexColumn.NextColumn(); | 
|        | 
|       while ( not isnull( indexColumn.NextColumn() ) ) { | 
|         productionSerialNumber := 1; | 
|         opcs                   := selectsortedset( indexColumn, OfflinePlanCell, tempOPC, tempOPC.FindType( "2", pl ), tempOPC.InventoryWeight() ); | 
|         if ( opcs.Size() > 0 ) { | 
|           // 判定1 | 
|           previousOPC := maxselect( previousColumn, OfflinePlanCell, tempOPC, tempOPC.FindType( "2", pl ), tempOPC.ProductionSerialNumber() ); | 
|           if ( isnull( previousOPC ) or indexColumn.ColumnDate() = macroPlan.StartOfPlanning().Date() ) { | 
|             opc := opcs.Element( 0 ); | 
|             opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) ); | 
|             opc.ProductionSerialNumber( productionSerialNumber ); | 
|             productionSerialNumber++; | 
|             opcs.Remove( opc ); | 
|           } else { | 
|             opc := select( opcs, Elements, tempOPC, tempOPC.OfflinePlanRow().ProductID() = previousOPC.OfflinePlanRow().ProductID() ); | 
|             if ( not isnull( opc ) ) { | 
|               opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) ); | 
|               opc.ProductionSerialNumber( productionSerialNumber ); | 
|               productionSerialNumber++; | 
|               opcs.Remove( opc ); | 
|             } | 
|           } | 
|            | 
|           // 判定2 | 
|           nextOPCs := selectset( opcs, Elements, tempOPC, | 
|                                  exists( nextColumn, OfflinePlanCell, nextOPC, nextOPC.FindType( "2", pl ) and nextOPC.OfflinePlanRow().ProductID() = tempOPC.OfflinePlanRow().ProductID() ) ); | 
|           if ( nextOPCs.Size() = 1 ) { | 
|             opc := nextOPCs.Element( 0 ); | 
|             opc.Value( "#" + opcs.Size().Format( "N(LPad0(2))" ) ); | 
|             opc.ProductionSerialNumber( opcs.Size() ); | 
|             opcs.Remove( opc ); | 
|           } | 
|            | 
|           // 判定3 | 
|           traverse ( opcs, Elements, opc ) { | 
|             opc.Value( "#" + productionSerialNumber.Format( "N(LPad0(2))" ) ); | 
|             opc.ProductionSerialNumber( productionSerialNumber ); | 
|             productionSerialNumber++; | 
|             opcs.Remove( opc ); | 
|           } | 
|         } | 
|          | 
|         indexColumn    := indexColumn.NextColumn(); | 
|         previousColumn := indexColumn.PreviousColumn(); | 
|         nextColumn     := indexColumn.NextColumn(); | 
|       } | 
|     } | 
|   *] | 
| } |