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' } 
 | 
} 
 |