chenqinghong
2024-05-07 3ec06a830367465068963156dcc1d8e522571c13
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
Quintiq file version 2.0
#parent: #root
Method InitConstraintsGoalsForDriverSales (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const LibOpt_Scope scope
) const
{
  Description: 'Init constraints goals for sales accounts'
  TextBody:
  [*
    // Sales revenue accounts
    salesdemandqty_varname := typeof( MPSalesDemandQtyVariable );
    driversales_varname := typeof( MPDriverSalesVariable );
    disaggregatedsalesdemandqty_varname := typeof( MPDisaggregatedSalesDemandQtyVariable );
    driversales_constname := typeof( MPDriverSalesConstraint );
    delayedsalesdemandqty_varname := typeof( MPDelayedSalesDemandQtyVariable );
    delayeddisaggregatedsalesdemandqty_varname := typeof( MPDelayedDisaggregatedSalesDemandQtyVariable );
    
    scalefactor_driver_revconst := this.ScaleConstraintTerm( driversales_varname, driversales_constname );
    scalefactor_salesdemandqty_revconst := this.ScaleConstraintTerm( salesdemandqty_varname, driversales_constname );
    scalefactor_disaggregatedsalesdemandqty_revconst := this.ScaleConstraintTerm( disaggregatedsalesdemandqty_varname, driversales_constname );
    scalefactor_delayedsalesdemandqty_revconst := this.ScaleConstraintTerm( delayedsalesdemandqty_varname, driversales_constname );
    scalefactor_delayeddisaggregatedsalesdemandqty_revconst := this.ScaleConstraintTerm( delayeddisaggregatedsalesdemandqty_varname, driversales_constname );
    
    
    scalefactor_rhs_revconst := this.ScaleConstraintRHS( driversales_constname, 1.0 );
    
    driver := select( this, MacroPlan.AccountCostDriver, driver, driver.Name() = Translations::MP_AccountAssignmentCostDriverSales() ); // unique
    traverse( scope.GetAccountsInOptimizerRunConst(),Elements, account, account.HasSalesAssignment() ) // condition -=> not isnull( driver )
    {
      // Sales of each account = sales demands & postponed sales demand fulfilled quantity in each assignment * revenue.
      // revconst constraint uom: Monetary
      revconst := program.DriverSalesConstraints().New( account, driver );
      revconst.Sense( '=' );
      revconst.RHSValue( 0.0 * scalefactor_rhs_revconst );
      // Term UoM: Monetary
      revconst.NewTerm( 1.0 * scalefactor_driver_revconst, program.DriverSalesVariables().Get( account, driver ) );
    
      traverse( account, AccountAssignment.astype( PISPAccount ), aa, aa.AccountCostDriver() = driver )
      {
        // The pispip should only be considered if it is part of this optimizer run
        pisp := aa.ProductInStockingPoint_MP();
        maxpostponementperiod := pisp.OptimizerMaxPostponementPeriod();
        
        if ( guard( scope.Contains(  aa.ProductInStockingPoint_MP().PISPInOptimizerRun() ) and pisp.IsLeaf(), false ) )
        {
          pispip := pisp.EarliestPISPIPInScope().astype( ProductInStockingPointInPeriodPlanningLeaf ); 
          lateststart := guard( pisp.LatestPISPIPInScope().Start(), DateTime::MinDateTime() ); 
          while ( not isnull( pispip ) and pispip.Start() <= lateststart ) 
          {
            traverse( pispip, PlanningBaseSalesDemandInPeriodForOptimization.astype( LeafSalesDemandInPeriod ), sd ) // traverse LeafSalesDemandInPeriod
            {
              // Term: -revenueperquantity * SalesDemandQty variable
              // UoM:     [Monetary/PISP]    *     [PISP]
              revconst.NewTerm( -sd.BasePricePerQuantity() * scalefactor_salesdemandqty_revconst, program.SalesDemandQtyVariables().Get( sd ) );
            } //end of traverse LeafSalesDemandInPeriod
      
            // No need to create any term for driver constraint on AggregatedSalesDemandInPeriod, therefore traverse DisaggregatedSalesDemandInPeriod
            traverse( pispip, PlanningBaseSalesDemandInPeriodForOptimization.astype( DisaggregatedSalesDemandInPeriod ), dasdip )
            {
              revconst.NewTerm( -dasdip.BasePricePerQuantity() * scalefactor_disaggregatedsalesdemandqty_revconst,
                                  program.DisaggregatedSalesDemandQtyVariables().Get( dasdip ) );                 
            } // end of traverse DisaggregatedSalesDemandInPeriod
            
            // Add terms for postponed sales demands
            previouspispip := pispip.PreviousPlanningPISPIP();
            
            for( i := 1;
                 i <= maxpostponementperiod         // within the maximum number of postponement periods
                 and not isnull( previouspispip );  // the previous pispip exists
                 i++
               )
            {
              traverse( previouspispip, astype( ProductInStockingPointInPeriodPlanningLeaf ).PlanningBaseSalesDemandInPeriodForOptimizationPostponable, sd,
                        not sd.MasterSalesDemand().IsExcludedFromFulfillmentKPI() )
              {
                isleafsalesdemandinperiod := sd.istype( LeafSalesDemandInPeriod );
                coefficient := ifexpr( isleafsalesdemandinperiod,
                                       -sd.BasePricePerQuantity(),
                                       -sd.astype( DisaggregatedSalesDemandInPeriod ).AggregatedSalesDemandInPeriod().BasePricePerQuantity() );
                scalefactor := ifexpr( isleafsalesdemandinperiod,
                                       scalefactor_delayedsalesdemandqty_revconst,
                                       scalefactor_delayeddisaggregatedsalesdemandqty_revconst );
                
                coeffactor := coefficient * scalefactor;
                
                var := sd.GetDelayedSalesDemandQtyVariable( program, pispip.Period_MP() );
                
                if( not isnull( var ) )
                {
                  revconst.NewTerm( coeffactor, var );
                }
              }
              
              previouspispip := previouspispip.PreviousPlanningPISPIP();
            }
            
            pispip := pispip.NextPlanningPISPIP().astype( ProductInStockingPointInPeriodPlanningLeaf );
          } // end of traverse pispip
        } // endif pisp
      } // end of traverse PISPAccount aa
    } // end of traverse optimizer accounts
  *]
  InterfaceProperties { Accessibility: 'Module' }
}