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() );
|
*]
|
}
|