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' } 
 | 
} 
 |