Quintiq file version 2.0 
 | 
#parent: #root 
 | 
Function CalcShelfLifeDDAgeQuantityIndexVectorAsBinaryValue 
 | 
{ 
 | 
  TextBody: 
 | 
  [* 
 | 
    // Firstly, we get use the vector that stores the age, qty at the start of the PISPIPPL (ShelfLifeSupplyAge/QtyVectorAsBinaryValue) 
 | 
    // Then we reserve the available product with the optimizer reserved qty, then we allocate the available product to dependent demand qty.  
 | 
    // *Available product: product that is not expired. 
 | 
    // Then we set add back the reserved product for optimizer reserved qty. 
 | 
    // Only then, we set the attribute to determine for each DD, which product will it get. As well as, what are the SLS after all DDs have been allocated. 
 | 
    // The logic will try to allocate the product stock according to optimizer fulfilled quantity. 
 | 
     
 | 
    // Example for product A, shelf life of 6 days. 
 | 
    // At the start of PISPIP, we have: { Age: 4, Qty: 10; Age: 5, Qty: 15; Age: 6, Qty: 20; Age: 7, Qty: 10 }  
 | 
    // The available product are only those with age <=6, which are { Age: 4, Qty: 10; Age: 5, Qty: 15; Age: 6, Qty: 20 } 
 | 
    // We have optimizer reserved qty of 5, so we'll reserve the youngest available product out first { Age: 4, Qty: 5 }, remaining to fulfill other demands { Age: 4, Qty: 5; Age: 5, Qty: 15; Age: 6, Qty: 20 } 
 | 
    // Then we have total DD of 25, so we'll allocate the oldest available product to the DD, remaining to fulfill other demands { Age: 4, Qty: 5, Age: 5, Qty: 10 } 
 | 
    // After these steps, we add back the optimizer reserved qty back to the vector, so the remaining vector including unavaiable product are { Age: 4, Qty: 10; Age: 5, Qty: 10; Age: 6, Qty: 0; Age: 7, Qty: 10 } 
 | 
    // Then, we remove those elements in the vector with qty of 0. Result: { Age: 4, Qty: 10; Age: 5, Qty: 10; Age: 7, Qty: 10 }. This is then set to the attribute ShelfLifeSupplyAfterDDAge/QtyVectorAsBinaryValue 
 | 
    // As a result from this method we also have attributes to determine for each DD, how many product of what age/qty will it get. E.g. DD 1 of Qty: 10 get { Age: 6, Qty: 10 }. DD2 of Qty 15 get { Age: 5, Qty: 5; Age: 6, Qty: 10 } 
 | 
    // In this case we have { index: 0, Age: 6, Qty: 10; index: 1, Age: 5, Qty: 5; index: 1, Age: 6, Qty: 10 } Note: Index 0 = DD 1; Index 1 = DD 2 
 | 
     
 | 
    // Construct the vectors for shelf-life dd 
 | 
    quantityvector := RealVector::Construct(); 
 | 
    agevector := RealVector::Construct(); 
 | 
    indexvector := NumberVector::Construct(); 
 | 
    pispippl := this.ProductInStockingPointInPeriodPlanningLeaf(); 
 | 
     
 | 
    // This is used to calculate the the fulfillable quantity of trip dependent demands 
 | 
    // Construct the vectors for shelf-life supply after dd 
 | 
    source_quantity_after_dd_vector := RealVector::Construct(); 
 | 
    source_age_after_dd_vector := RealVector::Construct(); 
 | 
     
 | 
    // Product stock quantity and age tracking is only needed if the Product has shelf life or maturation 
 | 
    product := pispippl.ProductInStockingPoint_MP().Product_MP(); 
 | 
    if( product.HasShelfLifeOrMaturation() ) 
 | 
    { 
 | 
     
 | 
      // Get source quantity and age vectors 
 | 
      source_quantityvector := RealVector::Construct( this.ShelfLifeSupplyQuantityVectorAsBinaryValue() ); 
 | 
      source_agevector := RealVector::Construct( this.ShelfLifeSupplyAgeVectorAsBinaryValue() ); 
 | 
     
 | 
      // The remaining supply that can be allocated to manual planning after deducting expired stock and optimizer fulfilled/reserved qty 
 | 
      remainingsupplyafteroptfulfilled := source_quantityvector.Sum() 
 | 
                                          - pispippl.ExpiredInPeriodShelfLifeSupplyQuantity() 
 | 
                                          - pispippl.OptimizerFulfilledDemandQuantity() 
 | 
                                          - pispippl.OptimizerReservedQuantity(); 
 | 
       
 | 
      // The quantity and age consumed by optimizer's quantity 
 | 
      source_quantityconsumedvector := RealVector::Construct(); 
 | 
      source_ageconsumedvector := RealVector::Construct(); 
 | 
       
 | 
      // Consider optimizer fulfilled sales demand qty first before allocating supplies to dependent demands 
 | 
      // such that sales demand will only consume the oldest stock 
 | 
      optfulfilled_sdqty := pispippl.GetOptimizerFulfilledSalesDemandQuantity(); 
 | 
      if( optfulfilled_sdqty > 0 ) 
 | 
      { 
 | 
        ShelfLife::SetAvailableAgeAndQuantityVectorAfterDemand( source_quantityvector, source_agevector, 
 | 
                                                                source_quantityconsumedvector, source_ageconsumedvector, 
 | 
                                                                optfulfilled_sdqty, 
 | 
                                                                false, // do not ignore maturation 
 | 
                                                                true, // reserve oldest product 
 | 
                                                                pispippl, 
 | 
                                                                0.0 // the passed in source_agevector has not been aged so there is need to un-age  
 | 
                                                                ); 
 | 
      } 
 | 
     
 | 
      // Since this is used to calculate the fulfillable quantity of trip dependent demands, it should use the same logic as CalcSystemFulfilledQuantity 
 | 
      optimizerreservedquantity := pispippl.OptimizerReservedQuantity(); 
 | 
      if( optimizerreservedquantity > 0 ) 
 | 
      { 
 | 
        ShelfLife::SetAvailableAgeAndQuantityVectorAfterDemand( source_quantityvector, source_agevector, 
 | 
                                                                source_quantityconsumedvector, source_ageconsumedvector, 
 | 
                                                                optimizerreservedquantity, 
 | 
                                                                true, // ignore maturation 
 | 
                                                                false, // reserve youngest product 
 | 
                                                                pispippl, 
 | 
                                                                0.0 // the passed in source_agevector has not been aged so there is need to un-age  
 | 
                                                              ); 
 | 
      } 
 | 
     
 | 
      source_agevectorsize := source_agevector.Size(); 
 | 
      // Sort the demands by period task lane leg first and then longest duration in trip 
 | 
      dependentdemands := ProductInStockingPointInPeriod::GetSortedDependentDemands( pispippl ); 
 | 
       
 | 
      // Traverse the dependent demands 
 | 
      traverse( dependentdemands, Elements, dependentdemand ) 
 | 
      { 
 | 
        dependentdemand.AllocateShelfLifeSupplyToDependentDemand( product, 
 | 
                                                                  dependentdemands, 
 | 
                                                                  // remaining supply after opt fulfilled will be reduced (if remaining supply is used) and output it back 
 | 
                                                                  remainingsupplyafteroptfulfilled, 
 | 
                                                                  source_quantityvector, 
 | 
                                                                  source_agevector, 
 | 
                                                                  source_agevectorsize, 
 | 
                                                                  quantityvector, 
 | 
                                                                  agevector, 
 | 
                                                                  indexvector ); 
 | 
      } 
 | 
       
 | 
      // Filter out elements that is less than or equals to 0 in quantity vector 
 | 
      isvalidvector := source_quantityvector.GreaterThan( 0.0 ); 
 | 
      source_quantityvector := source_quantityvector.GetSelection( isvalidvector ); 
 | 
      source_agevector := source_agevector.GetSelection( isvalidvector ); 
 | 
     
 | 
      // Reassign the optimizer reserved quantity back to the vectors 
 | 
      source_quantityvector.Append( source_quantityconsumedvector ); 
 | 
      source_agevector.Append( source_ageconsumedvector ); 
 | 
       
 | 
      // Sort the vectors 
 | 
      ShelfLife::SortAndMergeVectorAccordingToAge( source_quantityvector, source_agevector ); 
 | 
      source_quantity_after_dd_vector.Append( source_quantityvector ); 
 | 
      source_age_after_dd_vector.Append( source_agevector ); 
 | 
    } 
 | 
     
 | 
    this.ShelfLifeDDAgeVectorAsBinaryValue( agevector.AsBinaryValue() ); 
 | 
    this.ShelfLifeDDQuantityVectorAsBinaryValue( quantityvector.AsBinaryValue() ); 
 | 
    this.ShelfLifeDDIndexVectorAsBinaryValue( indexvector.AsBinaryValue() ); 
 | 
     
 | 
    this.ShelfLifeSupplyAfterDDAgeVectorAsBinaryValue( source_age_after_dd_vector.AsBinaryValue() ); 
 | 
    this.ShelfLifeSupplyAfterDDQuantityVectorAsBinaryValue( source_quantity_after_dd_vector.AsBinaryValue() ); 
 | 
  *] 
 | 
} 
 |