Quintiq file version 2.0 
 | 
#parent: #root 
 | 
StaticMethod AddSalesDemandsBeforeScope ( 
 | 
  LibOpt_Scope scope, 
 | 
  RunContextForCapacityPlanning runcontext 
 | 
) 
 | 
{ 
 | 
  TextBody: 
 | 
  [* 
 | 
    asdips := construct( AggregatedSalesDemandInPeriods ); 
 | 
    if ( runcontext.IsMetaIteration() )  
 | 
    { 
 | 
      SelectorMeta::ComputeFirstLastPISPIPInScope( scope ); // make sure to set these relations - we can limit to nonlead because leaf has already been done in smartplan gap fill 
 | 
    } 
 | 
     
 | 
    traverse( scope.GetProductInStockingPointInOptimizerRun(), Elements, pisp ) 
 | 
    { 
 | 
      maxpostponementperiod := pisp.OptimizerMaxPostponementPeriod(); 
 | 
       
 | 
      pispipstart := null( ProductInStockingPointInPeriodPlanning ); 
 | 
       
 | 
      if( runcontext.IsMetaIteration() ) 
 | 
      { 
 | 
        pispipstart := pisp.EarliestPISPIPInScope(); 
 | 
      } 
 | 
      else 
 | 
      { 
 | 
        pispipstart := minselect( pisp, ProductInStockingPointInPeriodPlanning, pispip, scope.Contains( pispip.PISPIPInOptimizerRun() ), pispip.Start() ); 
 | 
      } 
 | 
       
 | 
      periodstart := pispipstart.Period_MP(); 
 | 
       
 | 
      previouspispip := pispipstart.PreviousPlanningPISPIP(); 
 | 
       
 | 
      for( i := 1; 
 | 
           i <= maxpostponementperiod         // within the maximum number of postponement periods 
 | 
           and not isnull( previouspispip );  // the previous pispip exists 
 | 
           i++ 
 | 
         ) 
 | 
      { 
 | 
        // For non-aggregated demand, we can select directly 
 | 
        traverse( previouspispip, SalesDemandInPeriodBase.astype( LeafSalesDemandInPeriod ), lsdip, 
 | 
                  guard( lsdip.PostponementSpecification().IsValidData(), false ) 
 | 
                  and not lsdip.IsPostponed() 
 | 
                  and lsdip.CanOptimizeWhenPostponed( periodstart ) 
 | 
                  and lsdip.NeedsToBePlanned() 
 | 
                  and lsdip.IsWithinThresholdQuantity() 
 | 
                  and lsdip.GetIsPISPAndProductInOptimizerRun( scope, runcontext.IsPostProcessing() ) ) 
 | 
        { 
 | 
          scope.AddSDIPBeforeScope( lsdip ); 
 | 
          lsdip.SDIPBeforeScopeInRun().OptMinPostponementPeriod( periodstart.SequenceNrInPeriodSpecification() 
 | 
                                                                - lsdip.AsSalesDemandInPeriodBase().Period_MP().SequenceNrInPeriodSpecification() 
 | 
                                                               ); 
 | 
        } 
 | 
         
 | 
        // For aggregated demand, we need to select from the disaggregated demands, since the aggregated demand might have a different horizon 
 | 
        traverse( previouspispip, SalesDemandInPeriodBase.astype( DisaggregatedSalesDemandInPeriod ).AggregatedSalesDemandInPeriod, asdip, 
 | 
                  guard( asdip.PostponementSpecification().IsValidData(), false ) 
 | 
                  and not asdip.IsPostponed() 
 | 
                  and asdip.CanOptimizeWhenPostponed( periodstart ) 
 | 
                  and asdip.NeedsToBePlanned() 
 | 
                  and asdip.IsWithinThresholdQuantity() ) 
 | 
        { 
 | 
          asdips.Add( asdip ); 
 | 
        } 
 | 
         
 | 
        previouspispip := previouspispip.PreviousPlanningPISPIP(); 
 | 
      } 
 | 
    } 
 | 
     
 | 
    // The same aggregated SDIP may be selected multiple times from different disaggregated SDIPs, so get the unique ones. 
 | 
    uniqueasdips := asdips.Unique(); 
 | 
     
 | 
    traverse( uniqueasdips, Elements, asdip ) 
 | 
    { 
 | 
      scope.AddSDIPBeforeScope( asdip ); 
 | 
       
 | 
      // Since the horizons of the disaggregated sales demand PISPs may differ, we set the minimum value 
 | 
      asdip.SDIPBeforeScopeInRun().OptMinPostponementPeriod( 1 ); 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |