yanweiyuan3
2023-08-09 588bc7829387dfc761cc25f06f77d4c81818bd10
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
Quintiq file version 2.0
#parent: #root
Method CalculateSalesDemandFulfillmentOnHigherLevel
{
  TextBody:
  [*
    // Only "Propagate" the updated scope: The Product family
    updateScope := selectsortedset( this.ProductInStockingPoint_MP().GetAllParent(), Elements, e, 
                                    not e.IsLeaf() and e.SalesDemand( relsize ) > 0,
                                    -e.Product_MP().Level() );
    
    if( updateScope.Size() > 0 ) 
    {
      traverse( updateScope, Elements, e )
      {
        e.ResetSalesDemandFulfilledQuantity( this.Period_MP() );
      }
      
      // Propagate all PISPIP quantities before calculate for fulfillment on demand on higher level
      Transaction::Transaction().Propagate();
      
      // Initialize SystemRemainingQuantity
      traverse( updateScope, Elements.SalesDemand.SalesDemandInPeriod.astype( AggregatedSalesDemandInPeriod ), sdip )
      { 
        sdip.SystemRemainingQuantity( sdip.Quantity() - sdip.FulfilledQuantity() );
      }
      
      // Go through the PISPIP and onwards
      traverse( updateScope, Elements.ProductInStockingPointInPeriodPlanning, parentPispip, 
                parentPispip.Period_MP().SequenceNr() >= this.Period_MP().SequenceNr() )
      {
    
        traverse( parentPispip.GetLeavesOfProductDimension(), Elements.astype( ProductInStockingPointInPeriodPlanningLeaf ), pispip )
        {
          // The supply quantity will be updated when the algorithm used the supply to fulfill the demand in previous period.
          Transaction::Transaction().Propagate( attribute( ProductInStockingPointInPeriod, SupplyQuantity) );
          remainingQuantity := pispip.SupplyQuantity() 
                               /* We dont care about optimizer in this scope, manual planning will reset all optimizer fulfillments 
                               - pispip.OptimizerFulfilledDemandQuantity()  
                               - pispip.OptimizerReservedQuantity() */
                               
          // We don't allow total remaining qty to go below -ve
          // Although totalremaining = 0, still need to proceed with the greedy to reset the demands systemfulfilledquantity to 0
          remainingQuantity := maxvalue( remainingQuantity, 0.0 );
          
          // We will consider all Greedy algorithm sorting here which includes Leaf & Disaagregated sales demand in periods
          salesdemands := selectsortedset( pispip, PlanningBaseSalesDemandInPeriod, sd,
                                           sd.NeedsToBePlanned() and sd.IsNotRestricted(), //Should not consider DSDIP that is restricted by FR
                                           guard( -sd.Priority().Weight(), 0 ),
                                           -sd.BasePricePerQuantity(),
                                           ( not sd.MasterSalesDemand().IsLeaf() ).AsQUILL() /*Always fulfill leaf first*/ );
          
          traverse( salesdemands, Elements, sdip )
          { 
            ontype( sdip )
            {
              LeafSalesDemandInPeriod as leafsalesdemandinperiod:
              {
                // The fulfillment of the leaf sales demand in period will be assign by the greedy from PISPIP.CalcSystemFulfilledQuantity
                // We dont assign any fulfillment to leaf sales demand in period from here but only use it to reduce the totalremaining supply quantity
                qtyToFulfill := leafsalesdemandinperiod.Quantity();
                qtyAbleToFulfill := minvalue( remainingQuantity, qtyToFulfill );
                
                remainingQuantity := remainingQuantity - qtyAbleToFulfill;          
              }
              DisaggregatedSalesDemandInPeriod as disaggregatedsalesdemandinperiod:
              {
                qtyToFulfill := disaggregatedsalesdemandinperiod.AggregatedSalesDemandInPeriod().SystemRemainingQuantity();
                qtyAbleToFulfill := minvalue( remainingQuantity, qtyToFulfill );
    
                disaggregatedsalesdemandinperiod.SystemAssignedQuantity( qtyAbleToFulfill );
                disaggregatedsalesdemandinperiod.AggregatedSalesDemandInPeriod().SystemRemainingQuantity( qtyToFulfill - qtyAbleToFulfill );
                
                remainingQuantity := remainingQuantity - qtyAbleToFulfill; 
              }
            }
          }
        }
      }
    }
  *]
}