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() = "eMotor Assy (France)" // 测试本地场景时可以过滤 
 | 
    //           and u.Name() = "DL-MoMo"              // 测试实际场景时可以过滤 
 | 
              ) { 
 | 
      // 创建产线行 
 | 
      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 := oprQuantity.OfflinePlanCell( relnew, Value := [String]ns.Quantity().Round( 0 ), Shift := ns.PeriodTask_MP().UnitPeriod().astype( UnitPeriodTimeBase ).ShiftPattern().Name() ); 
 | 
          cellQuantity.OfflinePlanColumn( relset, opc ); 
 | 
          cellOrder := oprOrder.OfflinePlanCell( relnew,  
 | 
    //                                             Value := "单号" + [String]ns.Quantity().Round( 0 ) + "_" + [String]( ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() ), 
 | 
                                                 Value := [String]ns.Quantity().Round( 0 ), 
 | 
                                                 InventoryWeight := ns.ProductInStockingPointInPeriodPlanningLeaf().InventoryLevelEnd() - ns.ProductInStockingPointInPeriodPlanningLeaf().MinInventoryLevel() ); 
 | 
          cellOrder.OfflinePlanColumn( relset, opc ); 
 | 
        } 
 | 
      } 
 | 
       
 | 
      // 创建总量行 
 | 
      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 := opr.OfflinePlanCell( relnew, Value := opr.ProductionLine() ); 
 | 
        productLineCell.OfflinePlanColumn( relset, productOPC ); 
 | 
      } else if( opr.Type() = "1" ) { 
 | 
        productCell := opr.OfflinePlanCell( relnew, Value := opr.ProductID() + ifexpr( opr.Notes() = "", "", "-" + opr.Notes() ) ); 
 | 
        productCell.OfflinePlanColumn( relset, productOPC ); 
 | 
        typeCell    := opr.OfflinePlanCell( relnew, Value :=  "Quantity" ); 
 | 
        typeCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } else if ( opr.Type() = "2" ) { 
 | 
        typeCell    := opr.OfflinePlanCell( relnew, Value :=  "Order" ); 
 | 
        typeCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } else if ( opr.Type() = "3" ) { 
 | 
        totalCell := opr.OfflinePlanCell( relnew, Value := "合计" ); 
 | 
        totalCell.OfflinePlanColumn( relset, productOPC ); 
 | 
        totalCell := opr.OfflinePlanCell( relnew, Value :=  "总量" ); 
 | 
        totalCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } else if ( opr.Type() = "4" ) { 
 | 
        shiftCell := opr.OfflinePlanCell( relnew, Value :=  "班次" ); 
 | 
        shiftCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } else if ( opr.Type() = "5" ) { 
 | 
        shiftStartDateCell := opr.OfflinePlanCell( relnew, Value :=  "班次开始时间" ); 
 | 
        shiftStartDateCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } else if ( opr.Type() = "6" ) { 
 | 
        shiftEndDateCell := opr.OfflinePlanCell( relnew, Value :=  "班次结束时间" ); 
 | 
        shiftEndDateCell.OfflinePlanColumn( relset, typeOPC ); 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // 补全总量&班次&班次开始时间&班次结束时间 
 | 
    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 := totalOPR.OfflinePlanCell( relnew, Value := [String]total ); 
 | 
        totalCell.OfflinePlanColumn( relset, opc ); 
 | 
      } 
 | 
       
 | 
      // &班次 
 | 
      traverse ( shiftOPRs, Elements, shiftOPR ) { 
 | 
        shift := select( opc, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanRow().ProductionLine() = shiftOPR.ProductionLine() and tempOPC.OfflinePlanRow().Type() = "1" );  
 | 
        if ( not isnull( shift ) ) { 
 | 
          shiftCell := shiftOPR.OfflinePlanCell( relnew, Value := shift.Shift() ); 
 | 
          shiftCell.OfflinePlanColumn( relset, opc ); 
 | 
        } 
 | 
      } 
 | 
       
 | 
      // 班次开始时间 
 | 
      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 := ssdOPR.OfflinePlanCell( relnew, Value := startDate ); 
 | 
          startDateCell.OfflinePlanColumn( relset, opc ); 
 | 
        } 
 | 
      } 
 | 
       
 | 
      // 班次结束时间 
 | 
      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 := sedOPR.OfflinePlanCell( relnew, Value := endDate ); 
 | 
          endDateCell.OfflinePlanColumn( relset, opc ); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // 补全时间列 
 | 
    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; 
 | 
    } 
 | 
     
 | 
    // 补全空格子 
 | 
    traverse ( opt, OfflinePlanRow, opr ) { 
 | 
      traverse ( opt, OfflinePlanColumn, opc ) { 
 | 
        cell := select( opr, OfflinePlanCell, tempOPC, tempOPC.OfflinePlanColumn() = opc ); 
 | 
        if ( isnull( cell ) ) { 
 | 
          cell := opr.OfflinePlanCell( relnew, Value := "" ); 
 | 
          cell.OfflinePlanColumn( relset, opc ); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
     
 | 
    Transaction::Transaction().Propagate( attribute( OfflinePlanCell, Quantity ) ); 
 | 
    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() )  
 | 
    //          and indexColumn.ColumnDate() <= Date::Construct( 2020, 4, 1 ) // 测试实际场景时可以过滤 
 | 
             ) { 
 | 
        productionSerialNumber := 1; 
 | 
        opcs                   := selectsortedset( indexColumn, OfflinePlanCell, tempOPC, tempOPC.FindType( "2", pl ), tempOPC.InventoryWeight() ); 
 | 
        initialSize            := opcs.Size(); 
 | 
        info( "计划开始时间:", macroPlan.StartOfPlanning().Date().Format( "Y-M2-D2" ), "    索引时间:", indexDate.Format( "Y-M2-D2" ), "    个数:", opcs.Size() ); 
 | 
        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( "#" + initialSize.Format( "N(LPad0(2))" ) ); 
 | 
            opc.ProductionSerialNumber( initialSize ); 
 | 
            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(); 
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
} 
 |