| 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' } | 
| } |