| Quintiq file version 2.0 | 
| #parent: #root | 
| Method AddTermsToServiceLevelConstraints ( | 
|   CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program, | 
|   const constcontent BaseSalesDemandInPeriods bsdips, | 
|   Real scalefactor_salesdemandqty_constfromsd_det, | 
|   Real scalefactor_salesdemandqty_constfromsd_sto, | 
|   const LibOpt_Scope scope | 
| ) const | 
| { | 
|   Description: 'Add the sales demand term to the service level from sales demand constraints' | 
|   TextBody: | 
|   [* | 
|     // Only define the constraints if the sd needs to be planned and is on a pispip that is part of this optimizer run | 
|     traverse( bsdips,  | 
|               Elements,  | 
|               sd, | 
|               sd.NeedsToBePlanned() | 
|               and sd.IsWithinThresholdQuantity() ) | 
|     { | 
|       uomconversion := sd.DefaultUOMConversionFactor(); | 
|       ids := sd.ServiceLevelBaseIDs().Tokenize( ';' ); | 
|       traverse( ids, Elements, id, not id = '' ) | 
|       {  | 
|         sl := ServiceLevelBase::FindServiceLevelBaseTypeIndex( id );  | 
|         if ( sl.IsEnabled() )  | 
|         {         | 
|           constr := null(  MPConstraint );  | 
|           scalefactor := 0.0;  | 
|           if ( sl.IsUsedForPlanningFulfillmentSystem() ) | 
|           { | 
|             constr := program.FulfillmentTargetFromSDQtyConstraints().Get(  sl );   | 
|             scalefactor := scalefactor_salesdemandqty_constfromsd_det;  | 
|           } | 
|           else if ( sl.IsUsedForSafetyStockCalculation() )  | 
|           { | 
|             constr := program.ServiceLevelFromSDQtyConstraints().Get( sl ); | 
|             scalefactor := scalefactor_salesdemandqty_constfromsd_sto;  | 
|           } | 
|            | 
|           if ( not isnull( constr ) )  | 
|           {    | 
|             constr.Enabled( true ); // adding a term so make it enabled | 
|             if( sd.istype( LeafSalesDemandInPeriod ) ) | 
|             { | 
|                 constr.NewTerm( -uomconversion * scalefactor, program.SalesDemandQtyVariables().Get( sd.astype( LeafSalesDemandInPeriod ) ) ); | 
|             } | 
|             else if( sd.istype( DisaggregatedSalesDemandInPeriod ) ) | 
|             { | 
|                 constr.NewTerm( -uomconversion * scalefactor, program.DisaggregatedSalesDemandQtyVariables().Get( sd.astype( DisaggregatedSalesDemandInPeriod ) ) ); | 
|             } | 
|              | 
|             // track existing fulfilled qty. Then what is out of scope is computed | 
|             // by sl.TotalFulFilledQuantity - sl.OptimizerConstantTerm | 
|             var_workaround_const := program.Variable( 'OptimizerConstantTerm', sl );  | 
|             newvalue := var_workaround_const.UpperBound() + sd.FulfilledQuantityInDefaultUOM();  | 
|             this.StoreValueInVariable( var_workaround_const, newvalue );  | 
|           }                                                                                               | 
|         } // end if isenabled | 
|       } // traverse sl  | 
|     } | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |