haorenhui
2023-10-30 6d6cc10d9e8e242661da7fd655dec155a09d676c
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
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' }
}