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
Quintiq file version 2.0
#parent: #root
Method AddProductionTermMaturationSlackConstraint (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  MPConstraint matconstr,
  const ProductInStockingPoint_MP pisp,
  const ProductInStockingPointInPeriodPlanning pispip,
  const OutgoingShelfLifeDay oslday,
  Real scalefactor_mass,
  Real scalefactor_rhs_const,
  Boolean ismaturationforarrival
) const
{
  TextBody:
  [*
    extra_age := ifexpr( ismaturationforarrival, [Real]oslday.ShelfLifeDays(), 0.0 );       
    pispipforexpired := constnull(  ProductInStockingPointInPeriodPlanning ); 
    if ( pisp.IsOptShelfLife() ) 
    {
      product := pisp.Product_MP(); 
      periodpispip := pispip.Period_MP(); 
      // pick latest PISPIP prior to pispip where product will not be usable any more in 'pispip'. The cumulative waste there we need to discount 
      pispipforexpired := maxselect( pispip, 
                                     ProductInStockingPoint_MP.ProductInStockingPointInPeriodPlanning, 
                                     p, 
                                     p.Start() <= pispip.Start() 
                                     and not CapacityPlanningSuboptimizer::GetIsUsableInTargetPeriod( product, p.Period_MP(), periodpispip ), 
                                     p.Start() );
    }
    
    traverse( pisp, IncomingShelfLifeDay, islday ) 
    {
      // compute latest period "pispipearlier"  so that production will be mature for pispip and also will have arrived
      pispipearlier := maxselect( pisp, 
                                  ProductInStockingPointInPeriodPlanning, 
                                  p, 
                                  pisp.Product_MP().GetIsMaturedInTargetPeriod( extra_age, p.Start(), pispip.Period_MP() ) // add outgoing trip days because ok to be mature on arrival only
                                  and p.Start() + islday.ShelfLifeAsDuration() <= pispip.Start(), // product needs to be there
                                  p.Start() ); 
      
      
      if ( not isnull( pispipearlier ) ) 
      {
        cpvar := program.CumulativeProductionVariables().Find( pispipearlier, islday ) 
        if ( not isnull( cpvar ) ) 
        {
          matconstr.NewTerm( -1.0 * scalefactor_mass, cpvar ); 
        }
        else
        {
          matconstr.RHSValue( matconstr.RHSValue() + scalefactor_rhs_const* pispipearlier.GetCumulativeProduction( islday ) ); 
        }
      }
      
      // take out expired quantity, because this cannot count towards how much matured product is there
      if ( pisp.IsOptShelfLife() and not isnull( pispipforexpired ) ) 
      {  
        wvar := program.CumulativeWasteVariables().Find( pispipforexpired, islday )
        if ( not isnull( wvar ) ) 
        {
          matconstr.NewTerm(  1.0 * scalefactor_mass, wvar ); 
        }
      }
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}