| Quintiq file version 2.0 | 
| #parent: #root | 
| MethodOverride GetPeriodTasksToSearch ( | 
|   ProductInStockingPointInPeriodPlanningLeaf pispip, | 
|   LibOpt_Scope scope, | 
|   RunContextForCapacityPlanning runcontext, | 
|   Units units, | 
|   Boolean isusingselectedunits, | 
|   Number depth | 
| ) as owning PeriodTaskOperations | 
| { | 
|   TextBody: | 
|   [* | 
|     ptforrecursive := construct( PeriodTaskOperations );  | 
|     if ( runcontext.IsSmartPlan() ) | 
|     { | 
|       gp := pispip.MacroPlan().GlobalParameters_MP();       | 
|       period := pispip.Period_MP();  | 
|       operations := null(  Operations );  | 
|       // Traverse over the operations that take this product as an input | 
|       // If this product is a byproduct, we do not want to add its operations, unless they only take byproducts as inputs. | 
|       // This is to avoid adding products to the smart plan that are only related to the smart plan output pispips because they are input together with the same byproduct | 
|        | 
|       | 
|       operations := selectset( pispip, ProductInStockingPoint_MP.OperationInput.Operation, operation, | 
|                                operation.GetIsAvailableForOptimization()                                // The operation must be available | 
|                                and ( not pispip.ProductInStockingPoint_MP().Product_MP().IsDerivedByProduct()  // This product is not a byproduct | 
|                                      or operation.AllInputsAreDerivedByProducts() )   // or all inputs are byproducts | 
|                                and ( not isusingselectedunits or exists( units, Elements, unit, unit = operation.Unit() ) ) ) | 
|                                 | 
|       traverse( operations, Elements, operation )  | 
|       {  | 
|         // The period in which the period tasks occurs is the period from which the inputs are taken + the lead time | 
|         endofpt := period.PeriodEnd() + operation.LeadTime(); | 
|          | 
|         // If the operation lead time logic is either end of period or middle of period | 
|         // Then the end of the period task is calculated as the start of the dependent demand period plus the lead time | 
|         if( gp.IsOperationLeadTimeLogicFromEnd() or gp.IsOperationLeadTimeLogicFromMiddle() ) | 
|         { | 
|           endofpt := period.Start() + operation.LeadTime(); | 
|         } | 
|          | 
|         nsperiod := period.GetNewSupplyPeriod( endofpt ); | 
|      | 
|         // If the operation lead time logic is middle of the period | 
|         // Then the end of the period should be before the middle of the new supply period | 
|         // If this is not the case, then the new supply period should be the next period | 
|         if( gp.IsOperationLeadTimeLogicFromMiddle()  | 
|             and guard( endofpt >= nsperiod.End() - 0.5 * nsperiod.Duration(), false ) ) | 
|         { | 
|           nsperiod := guard( nsperiod.NextPlanningPeriod(), null( Period_MP ) ); | 
|         } | 
|       | 
|         if( not isnull( nsperiod )  | 
|             and PeriodTaskOperation::GetIsValidPeriodTask( operation, nsperiod ) )       // The resulting period task must be valid | 
|         {  | 
|           // Add the operations that can supply to this pispip to operationsforoptimization | 
|        | 
|           // Create/Select the related periodtaskoperation and add it to PTOperationsForOptimization | 
|           periodtaskoperation := PeriodTaskOperation::FindPeriodTaskOperationTypeIndex( nsperiod.Start() , operation.ID() ); | 
|        | 
|           if( isnull( periodtaskoperation ) ) | 
|           { | 
|             unit := operation.Unit();  | 
|             unitperiod := UnitPeriod::FindUnitPeriodTypeIndex( unit.ID(), period.Start(), period.End() ); | 
|             periodtaskoperation := PeriodTaskOperation::Create( operation, unitperiod, 0.0, false ); | 
|             // this transaction propagate is necessary, we need to get the new supply from the newly created periodtask | 
|             Transaction::Transaction().Propagate( relation( PeriodTaskOperation, NewSupply ) ); | 
|             Transaction::Transaction().Propagate( relation( PeriodTaskOperation, DependentDemand ) ); | 
|             Transaction::Transaction().Propagate( relation(  NewSupply, ProcessOutput ) );  | 
|             Transaction::Transaction().Propagate( relation(  DependentDemand, ProcessInput ) );  | 
|           } | 
|           ptforrecursive.Add( periodtaskoperation );  | 
|         } | 
|       }                  | 
|     } | 
|     else | 
|     { | 
|       // meta optimizer case | 
|       if ( this.LimitToNonzeroPlanning() )  | 
|       { | 
|         ptforrecursive := selectset( pispip, DependentDemandOperationForMeta.PeriodTaskOperation, pto, true, not pto.Quantity() = 0.0 );   | 
|         if (  pispip.ProductInStockingPoint_MP().Product_MP().IsDerivedByProduct() )  | 
|         { | 
|           ptforrecursive := selectset( ptforrecursive, Elements, pto, true, pto.Operation().AllInputsAreDerivedByProducts() );  | 
|         } | 
|       } | 
|       else | 
|       { | 
|         ptforrecursive := selectset( pispip, DependentDemandOperationForMeta.PeriodTaskOperation, pto, true, true );   | 
|         if (  pispip.ProductInStockingPoint_MP().Product_MP().IsDerivedByProduct() )  | 
|         { | 
|           ptforrecursive := selectset( ptforrecursive, Elements, pto, true, pto.Operation().AllInputsAreDerivedByProducts() );  | 
|         } | 
|         if ( this.OperationSelectLimit().IsFinite() )  | 
|         {                                                               | 
|           ptforrecursive.SelectFirst(  this.OperationSelectLimit() );                                                                 | 
|         }     | 
|       } | 
|     } | 
|     return & ptforrecursive | 
|   *] | 
| } |