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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
Quintiq file version 2.0
#parent: #root
Method OTSPrepareInventoryLevelTargetsBeforeScope (
  Date firstperioddate
)
{
  Description: 'Inventory targets ( min, max, safety ) prior to the optimizer scope are converted from target in days into absolute targets (having value equal to the current min / max / safety level).'
  TextBody:
  [*
    traverse( this, MacroPlan.Product_MP.ProductInStockingPoint_MP.ProductInStockingPointInPeriodPlanning, pispip ) 
    {
      pispip.DebugCheckOTSPreprocessingMax( pispip.MaxInventoryLevel() ); 
      pispip.DebugCheckOTSPreprocessingMin( pispip.MinInventoryLevel() ); 
      pispip.DebugCheckOTSPreprocessingSafety( pispip.TargetInventoryLevel() );   
    }
    
    traverse( this, MacroPlan.Product_MP, product ) 
    {
      traverse( product, ProductInStockingPoint_MP, pisp ) 
      {
        istoprocess := selectsortedset(  pisp, 
                                         InventorySpecification, 
                                         is, 
                                         ( is.HasMaxLevelInDays() or is.HasMinLevelInDays() ) and is.Start() < firstperioddate , 
                                         firstperioddate - is.Start() ); // go from later to earlier 
    
        firstinscopeis := InventorySpecification::FindInventorySpecificationTypeIndex( product.ID(), pisp.StockingPointID(), firstperioddate ); 
        if ( isnull( firstinscopeis ) and istoprocess.Size() > 0 ) 
        {
          is := istoprocess.Element( 0 ); // carry over information from last istoprocess in time 
          InventorySpecification::Create( product, 
                                        pisp.StockingPoint_MP(), 
                                        firstperioddate, 
                                        false, // hastargetindays
                                        0.0, // target in days
                                        0.0, // target in qty
                                        is.HasMinLevelInDays(), // hasminindays
                                        is.MinLevelInDays(), // min in days 
                                        is.MinLevelInQuantity(), // in in qty
                                        is.HasMaxLevel(), 
                                        is.HasMaxLevelInDays(), // has max level in days
                                        is.MaxLevelInDays(), // max level in days 
                                        is.MaxLevelInQuantity(), // max level in qty
                                        is.IsCalculated(), // is calculated
                                        is.IsManuallyConfigured() ); // is from db
        }
    
        lastdate := firstperioddate;                                        
        traverse( istoprocess, Elements, is )                             
        {
          sp := is.StockingPoint_MP(); 
          isstart := is.Start();
          hasmaxlevel := is.HasMaxLevel(); 
          manualconf := is.IsManuallyConfigured(); 
          
          is.Delete(); 
      
          traverse( this, MacroPlan.PlanningPeriod, period, period.StartDate() < lastdate and period.StartDate() >= isstart ) // up to where previous process is starts
          {
            pispip := select( pisp, ProductInStockingPointInPeriodPlanning, p, true, p.Start() = period.Start() );  
           
            mininqty := pispip.MinInventoryLevel();  
            maxinqty := pispip.MaxInventoryLevel(); 
            
            InventorySpecification::Create( product, 
                                            sp, 
                                            period.StartDate(), 
                                            false, // hastargetindays
                                            0.0, // target in days
                                            0.0, // target in qty
                                            false, // hasminindays
                                            0.0, // min in days 
                                            mininqty, // in in qty
                                            hasmaxlevel, 
                                            false, // has max level in days
                                            0.0, // max level in days 
                                            maxinqty, // max level in qty
                                            false, // is calculated
                                            manualconf ); // is from db
            
          } 
          lastdate := isstart; // end point for next iteration of traverse for InventorySpecification object                              
        }  
      
        safetytoprocess := selectsortedset(  pisp, SafetyStock, s, s.HasTargetInDays() and s.Start() < firstperioddate, firstperioddate - s.Start() ); // go from later to earlier 
    
        firstinscopess := SafetyStock::FindTypeIndexSafetyStock( product.ID(), pisp.StockingPointID(), firstperioddate ); 
        // check for safety stock starting on firsperiodate. If nothing then we should create a new one, otherwise ok
        if ( isnull( firstinscopess ) and safetytoprocess.Size() > 0 ) 
        {
          sstock := safetytoprocess.Element( 0 ); // carry over information from last safety stock before 'firstperioddate'
          SafetyStock::Create( product, 
                               pisp.StockingPoint_MP(), 
                               firstperioddate, 
                               sstock.HasTargetInDays(), // has target in days 
                               sstock.TargetInDays(), // target in days 
                               sstock.TargetInQuantity(), // target in qty
                               sstock.IsCalculated(), // is calculated 
                               sstock.HasUserTarget(), // has user target 
                               sstock.IsManuallyConfigured() ); 
        }
        
        lastdate := firstperioddate; 
        traverse( safetytoprocess, Elements, sstock ) 
        {
          sp := sstock.StockingPoint_MP(); 
          pisp := select( product, ProductInStockingPoint_MP, p, true, p.StockingPoint_MP() = sp ); 
          ismanual := sstock.IsManuallyConfigured(); 
          sstockstart := sstock.Start();
          hasuser := sstock.HasUserTarget(); 
       
          sstock.Delete(); 
          
          traverse( this, MacroPlan.PlanningPeriod, period, period.StartDate() < lastdate and period.StartDate() >= sstockstart ) 
          {
            pispip := select( pisp, ProductInStockingPointInPeriodPlanning, p, true, p.Start() = period.Start() );  
            
            slevel := pispip.TargetInventoryLevel(); 
    
            SafetyStock::Create( product, 
                                 sp, 
                                 period.StartDate(), 
                                 false, // has target in days 
                                 0.0, // target in days 
                                 slevel, // target in qty
                                 false, // is calculated 
                                 hasuser, // has user target 
                                 ismanual );
          }
          lastdate := sstockstart; // end point for next iteration of traverse on safety stock objects         
        }
      }    
    } 
    
    Transaction::Transaction().Propagate( attribute( ProductInStockingPointInPeriodPlanning, MinInventoryLevel ) ); 
    Transaction::Transaction().Propagate( attribute( ProductInStockingPointInPeriodPlanning, MaxInventoryLevel ) ); 
    Transaction::Transaction().Propagate( attribute( ProductInStockingPointInPeriodPlanning, TargetInventoryLevel ) ); 
    
    unchanged := true; 
    traverse( this, MacroPlan.Product_MP.ProductInStockingPoint_MP.ProductInStockingPointInPeriodPlanning, pispip ) 
    {
      if ( pispip.DebugCheckOTSPreprocessingMax() <> pispip.MaxInventoryLevel() ) 
      {
        unchanged := false; 
        debuginfo(  'Changed max', pispip.Start(), pispip.ProductInStockingPoint_MP().Name(), 'old=', pispip.DebugCheckOTSPreprocessingMax() , 'new=', pispip.MaxInventoryLevel() ); 
      } 
      if ( pispip.DebugCheckOTSPreprocessingMin() <> pispip.MinInventoryLevel() ) 
      {
        unchanged := false; 
        debuginfo(  'Changed min', pispip.Start(), pispip.ProductInStockingPoint_MP().Name(), 'old=', pispip.DebugCheckOTSPreprocessingMin() , 'new=', pispip.MinInventoryLevel() ); 
      }
      if ( pispip.DebugCheckOTSPreprocessingSafety() <> pispip.TargetInventoryLevel() )
      {
        unchanged := false; 
        debuginfo(  'Changed safety', pispip.Start(), pispip.ProductInStockingPoint_MP().Name(), 'old=', pispip.DebugCheckOTSPreprocessingSafety() , 'new=', pispip.TargetInventoryLevel() ); 
      } 
    }
    verify( unchanged, 'Failure to change inventory / safety stock in days' );
  *]
  InterfaceProperties { Accessibility: 'Module' }
}