yanweiyuan3
2023-08-09 588bc7829387dfc761cc25f06f77d4c81818bd10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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' }
}