| Quintiq file version 2.0 | 
| #parent: #root | 
| Method InitConstraintsForShelfLifeCumulativeDemand ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const ProductInStockingPointInPeriodPlanning pispip, | 
|   DateTime lastpispipstart, | 
|   DateTime firstafteractualstart, | 
|   const IncomingShelfLifeDay islday, | 
|   const LibOpt_Scope scope | 
| ) const | 
| { | 
|   Description: 'Initialize the constraints that are related to shelf life' | 
|   TextBody: | 
|   [* | 
|     cdconstname := typeof( MPCumulativeDemandConstraint ); | 
|     scalefactor_mass := this.ScaleConstraintTerm( typeof( MPSalesDemandQtyVariable ), cdconstname ); | 
|     scalefactor_rhs_constr := this.ScaleConstraintRHS( cdconstname, 1.0 );  | 
|      | 
|     previouspispip := pispip.PreviousPlanningPISPIP(); | 
|      | 
|     constr := program.CumulativeDemandConstraints().New( pispip, islday );  | 
|     constr.RHSValue( 0.0 );  | 
|     constr.Sense( '=' );  | 
|      | 
|     var := program.CumulativeDemandVariables().Find( previouspispip, islday );  | 
|     isfirstpispip := isnull( var );       | 
|      | 
|     if ( not isfirstpispip ) // once var = null then we are at the 1st period of extra pispip prior to opt horizon (for which we make sure we always have enough via method ShelfLifeExtendHistoricalPeriods | 
|     { | 
|        constr.NewTerm( 1.0 * scalefactor_mass, | 
|                        program.CumulativeDemandVariables().Get( previouspispip, islday ) ); | 
|     } | 
|      | 
|     // sales and dependent demand applicable for CP(pispip, *)  | 
|     pispipstoconsider := pispip.GetNextPISPIPWithinShelfLife( lastpispipstart ); // included pispip - still need to check for precise shelf life condition | 
|     product := pispip.ProductInStockingPoint_MP().Product_MP();  | 
|      | 
|     traverse( pispip, ProductInStockingPoint_MP.OutgoingShelfLifeDay, oslday )  | 
|     { | 
|       traverse( pispipstoconsider,  | 
|                 Elements,  | 
|                 pispipnext,     | 
|                 CapacityPlanningSuboptimizer::ShelfLifeFilterArrivedForDemand( pispip, pispipnext, islday )   | 
|                 and CapacityPlanningSuboptimizer::GetIsUsableInTargetPeriod( product, pispip.Period_MP(), pispipnext.GetTargetPeriod( oslday ) ) | 
|                 and ( isfirstpispip or not CapacityPlanningSuboptimizer::GetIsUsableInTargetPeriod( product, pispip.PreviousPlanningPISPIP().Period_MP(), pispipnext.GetTargetPeriod( oslday ) ) )  // only add what is new | 
|                 and ( pispipnext.Start() >= firstafteractualstart ) )  // exclude sales, dep. demand prior to actual if it exists ) | 
|       {  | 
|         constr.NewTerm( 1.0 * scalefactor_mass, program.DependentDemandInPISPIPShelfLifeVariables().Get( pispipnext, islday, oslday ) );  | 
|         if ( oslday.ShelfLifeDays() = 0 and not oslday.IsZeroShelfLifeDaysForTrips() ) // the dependent demand var does not include sales demand so add separately (considered as outgoing lead time 0 | 
|         { | 
|           traverse( pispipnext.GetLeafSalesDemandInPeriod(),  | 
|                     Elements,  | 
|                     lsdip,  | 
|                     not lsdip.IsPostponed() ) | 
|           { | 
|               svar := program.SalesDemandQtyVariables().Find( lsdip ); | 
|               if ( not isnull( svar ) )  | 
|               {  | 
|                 constr.NewTerm( 1.0 * scalefactor_mass, svar );  | 
|               } | 
|               else | 
|               { | 
|                 constr.RHSValue( constr.RHSValue() - scalefactor_rhs_constr * lsdip.FulfilledQuantity() );  | 
|               } | 
|           } | 
|            | 
|           // Postponed demands which are postponed to this period | 
|           previouspispip := pispipnext.PreviousPlanningPISPIP(); | 
|            | 
|           maxnumberofpostponement := pispipnext.ProductInStockingPoint_MP().OptimizerMaxPostponementPeriod(); // set in init instance for performance  | 
|           for( i := 1; | 
|                i <= maxnumberofpostponement       // within the maximum number of postponement periods | 
|                and not isnull( previouspispip );  // the previous pispip exists | 
|                i++ ) | 
|           { | 
|             traverse( previouspispip.astype( ProductInStockingPointInPeriodPlanningLeaf ), PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd ) | 
|             {                                              | 
|               delayedvar := sd.GetDelayedSalesDemandShelfLifeQtyVariable( program, pispipnext.Period_MP(), islday );  | 
|               if ( not isnull( delayedvar ) )  | 
|               { | 
|                 constr.NewTerm( 1.0 * scalefactor_mass, delayedvar );  | 
|               } | 
|             } | 
|             previouspispip := previouspispip.PreviousPlanningPISPIP();  | 
|           } | 
|         } | 
|       } | 
|     } | 
|     constr.NewTerm( -1.0 * scalefactor_mass, | 
|                    program.CumulativeDemandVariables().Get( pispip, islday )); | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |