| Quintiq file version 2.0 | 
| #parent: #root | 
| MethodOverride OnFinalize ( | 
|   LibOpt_Task task | 
| ) | 
| { | 
|   TextBody: | 
|   [* | 
|     macroplan := this.Optimization().astype( Optimization ).MacroPlan();  | 
|      | 
|     runcontext := RunContextForCapacityPlanning::GetRunContextCapacityPlanning( task.Run() );  | 
|     rcm := RunContextMeta::GetRunContextMeta( task.Run() );  | 
|      | 
|     this.Optimization().astype( Optimization ).SetMessageBenchmarking( runcontext );  | 
|      | 
|     if ( runcontext.UseShiftOptimization() )  | 
|     { | 
|       this.SetShiftPatterns( macroplan );  | 
|     } | 
|      | 
|     this.WriteScoresForAutoTestInstances( runcontext, task );  | 
|     this.DebugFinishForAutoTestInstances();   | 
|      | 
|     if ( runcontext.IsMetaIteration() )  | 
|     { | 
|       this.ApplyNoiseThreshold( task );  | 
|     } | 
|      | 
|     userperiodtasks := runcontext.GetUserPeriodTaskOperations();  | 
|     if ( not runcontext.IsSmartPlan() and not macroplan.Optimization().DebugMode() )  | 
|     { | 
|       this.RemoveUnusedOperationPeriodTaskAfterOptimizerRun( task.Scope(), runcontext, userperiodtasks ); | 
|       if ( guard( not runcontext.IsMetaIteration() or rcm.OptionCleanUpUnusedTripsPeriodTasksAfterwards(), false ) )  | 
|       { | 
|         this.RemoveUnusedTripsAfterOptimizerRun( task.Scope() ); | 
|       } | 
|     } | 
|      | 
|     if ( runcontext.UseCampaignSequenceOptimizer() and not macroplan.Optimization().DebugMode() )  | 
|     { | 
|       macroplan.Optimization().CampaignCombiGeneration().OptCampaign().Delete();   | 
|     } | 
|      | 
|     pisps := null(  ProductInStockingPoint_MPs, owning );  | 
|     if ( RunContextForCapacityPlanning::GetRunContextCapacityPlanning( task.Run() ).IsSmartPlan() )  | 
|     { | 
|       pisps := task.Scope().GetProductInStockingPointInOptimizerRun(); // for smart plan we want to make sure only to work on the relevant set for performance  | 
|     } | 
|     macroplan.Optimization().ShelfLifeExtendHistoricalPeriods( true, &pisps ); // restoring nr of historical periods (in case it was extended for shelf life)  | 
|      | 
|     macroplan.IsOptimizerRunning( false ); | 
|     macroplan.UpdateLastPlanningAction( false, true, false, false ); // isReset, isPlan, isRoll, isLockUnlock | 
|      | 
|     //Auto peg all demands to supplies using suggested quantity | 
|     if( macroplan.GlobalParameters_MP().IsPeggingRunAfterOptimization() ) | 
|     { | 
|       algorithmrun := macroplan.GetLastAlgorithmRun();  | 
|       algorithmrun.PeggingStart( DateTime::ActualTime() );  | 
|       //Propagate to create dependent demand and new supply, | 
|       //also calculate the values required for pegging (supply's quantity, demand's quantity, etc ) | 
|       Transaction::Transaction().Propagate(); | 
|       macroplan.RunPeggingAlgorithm(); | 
|      | 
|       algorithmrun.PeggingEnd( DateTime::ActualTime() );  | 
|     } | 
|     // Update the scaling | 
|      | 
|     if( runcontext.IsAutoScalingEnabled()  | 
|         and guard( rcm.OptionAllowScalingRecompute(), true )  ) | 
|     { | 
|       macroplan.UpdateScaling(); | 
|     } | 
|      | 
|     // Update KPI score | 
|     // Do not update the KPIs if this is the autotune copy, since it is only used for tuning and will be deleted after | 
|     // If performance is a concern, we can disable this and manually click on the Refresh KPI button during scenario comparison | 
|     Transaction::Transaction().Propagate(); // we need this because we potentially turned back on cost computation for meta | 
|     if( not runcontext.IsInventoryOptimizationRun() | 
|         or runcontext.IsFrozenRun() ) | 
|     { | 
|       if ( runcontext.IsSmartPlan() )  | 
|       { | 
|         macroplan.SmartPlanStartForUpdateKPI( runcontext.FirstPeriod_MP().Start() );  | 
|         isdownstream := not runcontext.IsUpstreamSmartPlan() and not runcontext.IsMiddleOutSmartPlan();  | 
|         smartplanpispips := task.Scope().GetSmartPlanPISPIPsInOptimizerRun();  | 
|         if ( isdownstream and smartplanpispips.Size() = 1 ) // for downstream we lock, but can only do it afterwards because the current supply is used | 
|         { | 
|           traverse( smartplanpispips, Elements.astype(  ProductInStockingPointInPeriodPlanningLeaf ), pispip )  | 
|           { | 
|             pispip.LockUnlock( true, false ); | 
|           } | 
|         } | 
|       } | 
|       if ( not runcontext.IsSync() ) // we cannot trigger a job when running sync | 
|       { | 
|         macroplan.CalculateKPIScore( runcontext.IsSmartPlan() ); | 
|       } | 
|       if( not runcontext.IsInventoryOptimizationRun() ) | 
|       { | 
|         info( 'End of propagation', DateTime::ActualTime() ); | 
|         info( '=======================================' );     // Seperator for each run | 
|       } | 
|     } | 
|      | 
|     if( not runcontext.IsInventoryOptimizationRun()  | 
|         and not ( runcontext.IsSmartPlan() and runcontext.IsSync() ) ) | 
|     { | 
|       debuginfo(  'Getting smmdsid and signal optimizer run completed' );  | 
|       macroplan.OptimizerRunCompleted(); | 
|     } | 
|   *] | 
| } |