admin
2025-01-22 7e31442f0e9b07764e9c6a9680d3d4aeba5fe1de
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
Quintiq file version 2.0
#parent: #root
Method CapacityPlanningAlgorithmHandleFeasibleSalesDemand (
  CapacityPlanningSuboptimizer_CapacityPlanningAlgorithm program,
  const RunContextForCapacityPlanning runcontext,
  LibOpt_Scope scope,
  ProductInStockingPointInPeriodPlannings pispipsinrun
)
{
  Description: 'Set the sales demand fulfillment quantity, and postpone sales demands if optimizer are allowed to do so, and choose to do so'
  TextBody:
  [*
    /*
    REMOVE := true; cmt := 'tmp';  
    if ( REMOVE ) 
    {
      count := 0; 
      traverse( this, MacroPlan.SalesDemand.SalesDemandInPeriod, s ) 
      {
        count++; 
        s.OptimizerMetaDebugOldFulfilledQuantity( s.FulfilledQuantity() ); 
        if ( count < 10 ) 
        {
          debuginfo( s.SalesSegmentName(), s.OptimizerMetaDebugOldFulfilledQuantity() ); 
        }
      }
    }
    */
    
    this.MergeSalesDemands(scope, pispipsinrun ); // removes postponed sd for all sd in scope (provided the postponedsd has its pispip in scope) 
    
    // Leaf Sales Demands 
    traverse( scope.GetLeafSalesDemandInPeriodInRun(), Elements, sd, isnull( sd.OriginalSalesDemand() ) or sd.IsManuallyPostponed() )
    {
      qty := this.GetOptimalValue( program.SalesDemandQtyVariables().Get( sd ) );
      sd.UpdateOptimizerFulfillment( true, qty );
      
      this.CapacityPlanningAlgorithmHandleFeasibleDelayedSalesDemand( sd, program, runcontext, scope, 1 );
    }
    
    // Aggregated sales demands for higher product level
    traverse( scope.GetAggregatedSalesDemandInPeriodInRun(), Elements, asdip ) // Aggregated does not have pisp asdip.ProductInStockingPoint_MP().GetIsInOptimizerRun()
    { 
      // No optimizer variables for AggregatedSalesDemandInPeriod
      // Traverse the children ( Disaggregated Sales demands )
      // skip postponed sales demand. Instead of using IsPostponed which requires a transaction propagate, we will just check for null OriginalSalesDemand
      traverse ( asdip, DisaggregatedSalesDemandInPeriod, dasdip, 
                 isnull( dasdip.OriginalSalesDemand() )
                 and scope.Contains( dasdip.AsPlanningBaseSalesDemandInPeriod().PISPIPInOptimizerRun() ) ) 
      {
        // Type    : DisaggregatedSalesDemandInPeriod
        // Variable: 'DisaggregatedSalesDemandQty' UoM: PISP
        var := this.GetOptimalValue( program.DisaggregatedSalesDemandQtyVariables().Get( dasdip ) );
        dasdip.UpdateOptimizerFulfillment( true, var );
        // Type    : DelayedDisaggregatedSalesDemandInPeriod
        // Variable: 'DelayedDisaggregatedSalesDemandQty' UoM: PISP
        this.CapacityPlanningAlgorithmHandleFeasibleDelayedSalesDemand( dasdip, program, runcontext, scope, 1 );
      }
    }
    
    // Sales demand before the optimization horizon, including those before the planning horizon.
    // Leaf sales demands
    traverse( scope.GetSDIPBeforeScopeInRun(), Elements.astype( LeafSalesDemandInPeriod ), lsdip )
    {
      this.CapacityPlanningAlgorithmHandleFeasibleDelayedSalesDemand( lsdip, program, runcontext, scope, lsdip.SDIPBeforeScopeInRun().OptMinPostponementPeriod() );
    }
    
    // Aggregated sales demands for higher product level
    traverse( scope.GetSDIPBeforeScopeInRun(), Elements.astype( AggregatedSalesDemandInPeriod ).DisaggregatedSalesDemandInPeriod, dasdip )
    {
      this.CapacityPlanningAlgorithmHandleFeasibleDelayedSalesDemand( dasdip, program, runcontext, scope,
                                                                      dasdip.AggregatedSalesDemandInPeriod().SDIPBeforeScopeInRun().OptMinPostponementPeriod() );
    }
  *]
  InterfaceProperties { Accessibility: 'Module' }
}