Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Method ShelfLifeCompleteSimple ( 
 | 
  LibOpt_Scope scope, 
 | 
  RunContextForCapacityPlanning runcontext 
 | 
) 
 | 
{ 
 | 
  TextBody: 
 | 
  [* 
 | 
    if ( this.Optimization().astype( Optimization ).MacroPlan().HasShelfLifeOrMaturation() )  
 | 
    { 
 | 
      pispipsadded := construct( ProductInStockingPointInPeriodPlanningLeafs );  
 | 
       
 | 
       
 | 
      pisps := selectset(  scope.GetPISPIPInOptimizerRun(),  
 | 
                           Elements.ProductInStockingPoint_MP,  
 | 
                           pisp,  
 | 
                           true,  
 | 
                           pisp.IsOptShelfLife() or pisp.IsOptMaturation()  ); // don't have pisp in scope yet, so get them via the pispips  
 | 
       
 | 
      debuginfo(  'Completing dependent demand for ', pisps.Size(), ' pisp(s)' );  
 | 
     
 | 
      // first complete the horizon at the end, because we don't know how to add constraints to deal with expiration past the scope 
 | 
      traverse( pisps, Elements, pisp )  
 | 
      { 
 | 
          current := pisp.LatestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
          while ( not isnull( current) )  
 | 
          { 
 | 
            scope.Add( current );  
 | 
            pisp.LatestPISPIPInScope( relset, current );  
 | 
            current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
          } 
 | 
      } 
 | 
       
 | 
      traverse( pisps, Elements, pisp )  
 | 
      { 
 | 
          current := pisp.EarliestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
           
 | 
          while ( not isnull( current) and not current.Period_MP().IsHistorical() )  
 | 
          { 
 | 
            scope.Add( current );  
 | 
            pisp.EarliestPISPIPInScope( relset, current );  
 | 
            current := current.PreviousPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
          } 
 | 
      } 
 | 
       
 | 
      // add in all trip & operation demand, becuase in the curren implementation we cannot take it out in a RHS of the constraints 
 | 
      // note it suffices to add pispips, pit, trip, periodtaskoperation, operation. Other object are added via pispips in method .CompleteFor_PISPIP() 
 | 
      traverse( pisps, Elements, pisp )  
 | 
      { 
 | 
          current := pisp.EarliestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
          laststart := pisp.LatestPISPIPInScope().Start();  
 | 
          while ( not isnull( current) and current.Start() <= laststart )  
 | 
          { 
 | 
            // add trip demand 
 | 
            traverse( current, DependentDemandTrip.ProductInTrip, pit )  
 | 
            { 
 | 
              arrivalpispip := pit.ArrivalPISPIP();  
 | 
              scope.Add( pit );  
 | 
              scope.Add( pit.Trip() );  
 | 
              scope.Add(  arrivalpispip ); 
 | 
              scope.Add( arrivalpispip.Period_MP() );   
 | 
              pispipsadded.Add( arrivalpispip );  
 | 
            } 
 | 
             
 | 
            // add operation demand 
 | 
            traverse( current, DependentDemandOperation.PeriodTaskOperation, pto, PeriodTaskOperation::GetIsValidPeriodTask( pto.Operation(), pto.UnitPeriod().Period_MP() ) )  
 | 
            { 
 | 
              scope.Add( pto.Operation() );  
 | 
              scope.Add( pto );  
 | 
              traverse( pto, NewSupply.ProductInStockingPointInPeriodPlanningLeaf, nspispip )  
 | 
              { 
 | 
                scope.Add( nspispip );  
 | 
                pispipsadded.Add( nspispip);   
 | 
              } 
 | 
            } 
 | 
             
 | 
            current := current.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );  
 | 
          } 
 | 
      } 
 | 
       
 | 
      // now repair gapfilling due to having added arrival pispips                                                       
 | 
       
 | 
      // recompute earliest latest pispip relation on pisp ( current method is called after gapfill)                      
 | 
      changed := construct( ProductInStockingPoint_MPs );  
 | 
      traverse( pispipsadded, Elements, pispip )  
 | 
      { 
 | 
        pisp := pispip.ProductInStockingPoint_MP();  
 | 
         
 | 
        if ( guard( pispip.Start() > pisp.LatestPISPIPInScope().Start(), true ) ) 
 | 
        { 
 | 
          pisp.LatestPISPIPInScope( relset, pispip ); 
 | 
          changed.Add( pisp );   
 | 
        } 
 | 
        if ( guard( pispip.Start() < pisp.EarliestPISPIPInScope().Start(), true ) ) 
 | 
        { 
 | 
          pisp.EarliestPISPIPInScope( relset, pispip );  
 | 
          changed.Add( pisp );  
 | 
        } 
 | 
      } 
 | 
       
 | 
      changed := changed.Unique();  
 | 
      debuginfo(  'Repairing gapsfill property for :', changed.Size(), ' pisp(s)' );  
 | 
     
 | 
      traverse( changed, Elements, pisp ) 
 | 
      { 
 | 
        firstpispip := pisp.EarliestPISPIPInScope();  
 | 
        lastpispip := pisp.LatestPISPIPInScope();  
 | 
       
 | 
        currentpispip := firstpispip;  
 | 
        while( not isnull( currentpispip )  
 | 
               and currentpispip.Start() < lastpispip.Start() )  
 | 
        { 
 | 
          if ( not scope.Contains( currentpispip.PISPIPInOptimizerRun() ) )  
 | 
          { 
 | 
            scope.Add( currentpispip ); // we want to avoid calling this if the pispip is already in scope for performance 
 | 
          }  
 | 
          currentpispip := currentpispip.NextPlanningPISPIP(); 
 | 
        } 
 | 
      } 
 | 
    } 
 | 
  *] 
 | 
  InterfaceProperties { Accessibility: 'Module' } 
 | 
} 
 |