Преглед изворни кода

Continuing the integration of the new data model...

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@544 a333f486-631f-4898-b8df-5754b55c2be0
dflaven пре 15 година
родитељ
комит
01d5ae9f93

+ 2 - 2
application/cmdbabstract.class.inc.php

@@ -150,7 +150,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 					$aParams = array(
 						'target_attr' => $oAttDef->GetExtKeyToMe(),
 						'object_id' => $this->GetKey(),
-						'menu' => false,
+						'menu' => true,
 						);
 				}
 				else
@@ -165,7 +165,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 							'object_id' => $this->GetKey(),
 							'target_attr' => $oAttDef->GetExtKeyToRemote(),
 							'view_link' => false,
-							'menu' => false,
+							'menu' => true,
 						);
 				}
 				$oPage->p("<img src=\"".MetaModel::GetClassIcon($sTargetClass)."\" style=\"vertical-align:middle;\">&nbsp;".$oAttDef->GetDescription());

+ 63 - 0
core/attributedef.class.inc.php

@@ -1166,6 +1166,13 @@ class AttributeDateTime extends AttributeDBField
 	public function GetTypeDesc() {return "Date and time";}
 	public function GetEditClass() {return "DateTime";}
 	protected function GetSQLCol() {return "TIMESTAMP";}
+	public static function GetAsUnixSeconds($value)
+	{
+		$oDeadlineDateTime = new DateTime($value, self::$const_TIMEZONE);
+		$iUnixSeconds = $oDeadlineDateTime->format('U');
+		return $iUnixSeconds;
+		
+	}
 
 	// #@# THIS HAS TO REVISED
 	// Having null not allowed was interpreted by mySQL
@@ -1294,7 +1301,63 @@ class AttributeDateTime extends AttributeDBField
 		return '"'.$sEscaped.'"';
 	}
 }
+/**
+ * A dead line stored as a date & time
+ * The only difference with the DateTime attribute is the display:
+ * relative to the current time
+ */
+class AttributeDeadline extends AttributeDateTime
+{
+	public function GetAsHTML($value)
+	{
+		$sResult = '';
+		if ($value !== null)
+		{
+			$value = AttributeDateTime::GetAsUnixSeconds($value);
+			$difference = $value - time();
+	
+			if ($difference >= 0)
+			{
+				$sResult = self::FormatDuration($difference);
+			}
+			else
+			{
+				$sResult = Dict::Format('UI:DeadlineMissedBy_duration', self::FormatDuration(-$difference));
+			}
+		}
+		return $sResult;
+	}
 
+	static function FormatDuration($duration)
+	{
+		$days = floor($duration / 86400);
+		$hours = floor(($duration - (86400*$days)) / 3600);
+		$minutes = floor(($duration - (86400*$days + 3600*$hours)) / 60);
+		$sResult = '';
+		
+		if ($duration < 60)
+		{
+			// Less than 1 min
+			$sResult =Dict::S('UI:Deadline_LessThan1Min');			
+		}
+		else if ($duration < 3600)
+		{
+			// less than 1 hour, display it in minutes
+			$sResult =Dict::Format('UI:Deadline_Minutes', $minutes);			
+		}
+		else if ($duration < 86400)
+		{
+			// Less that 1 day, display it in hours/minutes	
+			$sResult =Dict::Format('UI:Deadline_Hours_Minutes', $hours, $minutes);			
+		}
+		else
+		{
+			// Less that 1 day, display it in hours/minutes	
+			$sResult =Dict::Format('UI:Deadline_Days_Hours_Minutes', $days, $hours, $minutes);			
+		}
+		return $sResult;
+	}
+}
 // Init static constant once for all (remove when PHP allows real static const)
 AttributeDateTime::InitStatics();
 

+ 6 - 0
dictionaries/dictionary.itop.ui.php

@@ -797,6 +797,12 @@ When associated with a trigger, each action is given an "order" number, specifyi
 	'UI:OpenDocumentInNewWindow_' => 'Open this document in a new window: %1$s',
 	'UI:DownloadDocument_' => 'Download this document: %1$s',
 	'UI:Document:NoPreview' => 'No preview is available for this type of document',
+
+	'UI:DeadlineMissedBy_duration' => 'Missed  by %1$s',
+	'UI:Deadline_LessThan1Min' => '< 1 min',		
+	'UI:Deadline_Minutes' => '%1$d min',			
+	'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',			
+	'UI:Deadline_Days_Hours_Minutes' => '%1$dd %2$dh %3$dmin',
 ));
 
 

+ 6 - 0
dictionaries/fr.dictionary.itop.ui.php

@@ -799,6 +799,12 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
 	'UI:iTopVersion:Short' => 'iTop version %1$s',
 	'UI:iTopVersion:Long' => 'iTop version %1$s-%2$s du %3$s',
 
+	'UI:DeadlineMissedBy_duration' => 'Passé de %1$s',
+	'UI:Deadline_LessThan1Min' => '< 1 min',		
+	'UI:Deadline_Minutes' => '%1$d min',			
+	'UI:Deadline_Hours_Minutes' => '%1$dh %2$dmin',			
+	'UI:Deadline_Days_Hours_Minutes' => '%1$dj %2$dh %3$dmin',
+
 ));
 
 ?>

+ 54 - 0
modules/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php

@@ -26,6 +26,8 @@
 require_once('../application/cmdbabstract.class.inc.php');
 require_once('../application/template.class.inc.php');
 
+MetaModel::RegisterRelation("impacts", array("description"=>"Objects impacted by", "verb_down"=>"impacts", "verb_up"=>"is impacted by"));
+
 class Organization extends cmdbAbstractObject
 {
 
@@ -660,6 +662,20 @@ abstract class FunctionalCI extends cmdbAbstractObject
 		MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'owner_id', 'importance'));
 		MetaModel::Init_SetZListItems('list', array('status', 'owner_id', 'importance'));
 	}
+
+	public static function GetRelationQueries($sRelCode)
+	{
+		switch ($sRelCode)
+		{
+		case "impacts":
+			$aRels = array(
+				"contact" => array("sQuery"=>"SELECT Contact AS c JOIN lnkCIToContact AS l1 ON l1.contact_id = c.id WHERE l1.ci_id = :this->id", "bPropagate"=>true, "iDistance"=>3),
+				"solution" => array("sQuery"=>"SELECT ApplicationSolution AS s JOIN lnkSolutionToCI AS l1 ON l1.solution_id = s.id WHERE l1.ci_id = :this->id", "bPropagate"=>true, "iDistance"=>2),
+			);
+			return array_merge($aRels, parent::GetRelationQueries($sRelCode));
+		}
+	}
+	
 }
 class ApplicationInstance extends FunctionalCI
 {
@@ -695,7 +711,21 @@ class ApplicationInstance extends FunctionalCI
 		MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'owner_id', 'importance', 'device_id', 'licence_id', 'application_id', 'version', 'description'));
 		MetaModel::Init_SetZListItems('list', array('status', 'owner_id', 'importance', 'device_id', 'licence_id', 'application_id', 'version', 'description'));
 	}
+
+	public static function GetRelationQueries($sRelCode)
+	{
+		switch ($sRelCode)
+		{
+		case "impacts":
+			$aRels = array(
+				// Actually this should be limited to the ApplicationInstances based on a DBServer Application type...
+				"db_instances" => array("sQuery"=>"SELECT DatabaseInstance AS db WHERE db.db_server_instance_id = :this->id", "bPropagate"=>true, "iDistance"=>5),
+			);
+			return array_merge($aRels, parent::GetRelationQueries($sRelCode));
+		}
+	}
 }
+
 class DatabaseInstance extends FunctionalCI
 {
 
@@ -758,6 +788,18 @@ class ApplicationSolution extends FunctionalCI
 		MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'owner_id', 'importance', 'description'));
 		MetaModel::Init_SetZListItems('list', array('status', 'owner_id', 'importance', 'description'));
 	}
+	
+	public static function GetRelationQueries($sRelCode)
+	{
+		switch ($sRelCode)
+		{
+		case "impacts":
+			$aRels = array(
+				"process" => array("sQuery"=>"SELECT BusinessProcess AS p JOIN lnkProcessToSolution AS l1 ON l1.process_id = p.id WHERE l1.solution_id = :this->id", "bPropagate"=>true, "iDistance"=>3),
+			);
+			return array_merge($aRels, parent::GetRelationQueries($sRelCode));
+		}
+	}
 }
 class BusinessProcess extends FunctionalCI
 {
@@ -883,6 +925,18 @@ abstract class Device extends ConnectableCI
 		MetaModel::Init_SetZListItems('standard_search', array('name', 'status', 'owner_id', 'importance', 'brand', 'model', 'serial_number', 'asset_ref'));
 		MetaModel::Init_SetZListItems('list', array('status', 'owner_id', 'importance', 'brand', 'model', 'serial_number', 'asset_ref'));
 	}
+	
+	public static function GetRelationQueries($sRelCode)
+	{
+		switch ($sRelCode)
+		{
+		case "impacts":
+			$aRels = array(
+				"applications" => array("sQuery"=>"SELECT ApplicationInstance AS app WHERE app.device_id = :this->id", "bPropagate"=>true, "iDistance"=>5),
+			);
+			return array_merge($aRels, parent::GetRelationQueries($sRelCode));
+		}
+	}
 }
 class PC extends Device
 {

+ 104 - 65
modules/itop-tickets-1.0.0/model.itop-tickets.php

@@ -202,14 +202,14 @@ class Incident extends Ticket
 		MetaModel::Init_AddAttribute(new AttributeDateTime("closure_date", array("allowed_values"=>null, "sql"=>"closure_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeDateTime("last_update", array("allowed_values"=>null, "sql"=>"last_update", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeDateTime("assignment_date", array("allowed_values"=>null, "sql"=>"assignment_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeDateTime("escalation_deadline", array("allowed_values"=>null, "sql"=>"escalation_deadline", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeDateTime("closure_deadline", array("allowed_values"=>null, "sql"=>"closure_deadline", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
+		MetaModel::Init_AddAttribute(new AttributeDeadline("escalation_deadline", array("allowed_values"=>null, "sql"=>"escalation_deadline", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
+		MetaModel::Init_AddAttribute(new AttributeDeadline("closure_deadline", array("allowed_values"=>null, "sql"=>"closure_deadline", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeEnum("resolution_code", array("allowed_values"=>new ValueSetEnum('fixed,duplicate,couldnotreproduce,irrelevant'), "sql"=>"resolution_code", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeText("solution", array("allowed_values"=>null, "sql"=>"solution", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeEnum("user_satisfaction", array("allowed_values"=>new ValueSetEnum('1,2,3,4'), "sql"=>"user_satisfaction", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeText("user_commment", array("allowed_values"=>null, "sql"=>"user_commment", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
 
-		MetaModel::Init_SetZListItems('details', array('ref', 'title', 'ticket_log', 'start_date', 'document_list', 'ci_list', 'contact_list', 'status', 'caller_id', 'customer_id', 'service_id', 'servicesubcategory_id', 'product', 'impact', 'urgency', 'priority', 'workgroup_id', 'agent_id', 'agent_email', 'related_problem_id', 'related_change_id', 'closure_date', 'last_update', 'assignment_date', 'escalation_deadline', 'closure_deadline', 'resolution_code', 'solution', 'user_satisfaction', 'user_commment'));
+		MetaModel::Init_SetZListItems('details', array('ref', 'title', 'ticket_log', 'start_date', 'escalation_deadline', 'closure_deadline', 'document_list', 'ci_list', 'contact_list', 'status', 'caller_id', 'customer_id', 'service_id', 'servicesubcategory_id', 'product', 'impact', 'urgency', 'priority', 'workgroup_id', 'agent_id', 'agent_email', 'related_problem_id', 'related_change_id', 'closure_date', 'last_update', 'assignment_date', 'escalation_deadline', 'closure_deadline', 'resolution_code', 'solution', 'user_satisfaction', 'user_commment'));
 		MetaModel::Init_SetZListItems('advanced_search', array('ref', 'title', 'ticket_log', 'start_date', 'status', 'caller_id', 'customer_id', 'service_id', 'servicesubcategory_id', 'product', 'impact', 'urgency', 'priority', 'workgroup_id', 'agent_id', 'agent_email', 'related_problem_id', 'related_change_id', 'closure_date', 'last_update', 'assignment_date', 'escalation_deadline', 'closure_deadline', 'resolution_code', 'solution', 'user_satisfaction', 'user_commment'));
 		MetaModel::Init_SetZListItems('standard_search', array('ref', 'title', 'ticket_log', 'start_date', 'status', 'caller_id', 'customer_id', 'service_id', 'servicesubcategory_id', 'product', 'impact', 'urgency', 'priority', 'workgroup_id', 'agent_id', 'agent_email', 'related_problem_id', 'related_change_id', 'closure_date', 'last_update', 'assignment_date', 'escalation_deadline', 'closure_deadline', 'resolution_code', 'solution', 'user_satisfaction', 'user_commment'));
 		MetaModel::Init_SetZListItems('list', array('ref', 'title', 'ticket_log', 'start_date', 'status', 'caller_id', 'customer_id', 'service_id', 'servicesubcategory_id', 'product', 'impact', 'urgency', 'priority', 'workgroup_id', 'agent_id', 'agent_email', 'related_problem_id', 'related_change_id', 'closure_date', 'last_update', 'assignment_date', 'escalation_deadline', 'closure_deadline', 'resolution_code', 'solution', 'user_satisfaction', 'user_commment'));
@@ -225,7 +225,7 @@ class Incident extends Ticket
 					'start_date' => OPT_ATT_READONLY,
 					'last_update' => OPT_ATT_READONLY,
 					'assignment_date' => OPT_ATT_HIDDEN,
-					'escalation_deadline' => OPT_ATT_HIDDEN,
+					'escalation_deadline' => OPT_ATT_READONLY,
 					'closure_deadline' => OPT_ATT_HIDDEN,
 					'closure_date' => OPT_ATT_HIDDEN,
 					'customer_id' => OPT_ATT_MUSTCHANGE,
@@ -262,6 +262,8 @@ class Incident extends Ticket
 					'agent_id' => OPT_ATT_MANDATORY,
 					'related_problem_id' => OPT_ATT_NORMAL,
 					'related_change_id' => OPT_ATT_NORMAL,
+					'closure_deadline' => OPT_ATT_READONLY,
+					'escalation_deadline' => OPT_ATT_HIDDEN,
 				),
 			)
 		);
@@ -316,69 +318,79 @@ class Incident extends Ticket
 		MetaModel::Init_DefineTransition("resolved", "ev_close", array("target_state"=>"closed", "actions"=>array(), "user_restriction"=>null));
 	}
 
+	/**
+	 * Determines the shortest SLT, for this ticket, for the given metric. Returns null is no SLT was found
+	 * @param string $sMetric Type of metric 'TTO', 'TTR', etc as defined in the SLT class
+	 * @return hash Array with 'SLT' => name of the SLT selected, 'value' => duration in seconds of the SLT metric, null if no SLT applies to this ticket
+	 */
 	public function ComputeSLT($sMetric = 'TTO')
 	{
-		$sOQL = "SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id 
-				WHERE SLT.ticket_priority = :priority AND SLA.service_id = :service_id AND SLT.metric = :metric AND CustomerContract.customer_id = :customer_id";
-		$oSLTSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
-						array(),
-						array(
-							'priority' => $this->Get('priority'),
-							'service_id' => $this->Get('service_id'),
-							'metric' => $sMetric,
-							'customer_id' => $this->Get('customer_id'),
-						)
-						);
-						
-		$iMinDuration = PHP_INT_MAX;
-		$sSLTName = '';
-
-		while($oSLT = $oSLTSet->Fetch())
+		$aResult = null;
+		if (MetaModel::IsValidClass('SLT'))
 		{
-			$iDuration = $oSLT->Get('value');
-			$sUnit = $oSLT->Get('value_unit');
-			switch($sUnit)
+			$sOQL = "SELECT SLT JOIN lnkSLTToSLA AS L1 ON L1.slt_id=SLT.id JOIN SLA ON L1.sla_id = SLA.id JOIN lnkContractToSLA AS L2 ON L2.sla_id = SLA.id JOIN CustomerContract ON L2.contract_id = CustomerContract.id 
+					WHERE SLT.ticket_priority = :priority AND SLA.service_id = :service_id AND SLT.metric = :metric AND CustomerContract.customer_id = :customer_id";
+			$oSLTSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
+							array(),
+							array(
+								'priority' => $this->Get('priority'),
+								'service_id' => $this->Get('service_id'),
+								'metric' => $sMetric,
+								'customer_id' => $this->Get('customer_id'),
+							)
+							);
+							
+			$iMinDuration = PHP_INT_MAX;
+			$sSLTName = '';
+	
+			while($oSLT = $oSLTSet->Fetch())
 			{
-				case 'days':
-				$iDuration = $iDuration * 24; // 24 hours in 1 days
-				// Fall though
-				
-				case 'hours':
-				$iDuration = $iDuration * 60; // 60 minutes in 1 hour
-				// Fall though
-				
-				case 'minutes':
-				$iDuration = $iDuration * 60;
+				$iDuration = $oSLT->Get('value');
+				$sUnit = $oSLT->Get('value_unit');
+				switch($sUnit)
+				{
+					case 'days':
+					$iDuration = $iDuration * 24; // 24 hours in 1 days
+					// Fall though
+					
+					case 'hours':
+					$iDuration = $iDuration * 60; // 60 minutes in 1 hour
+					// Fall though
+					
+					case 'minutes':
+					$iDuration = $iDuration * 60;
+				}
+				if ($iDuration < $iMinDuration)
+				{
+					$iMinDuration = $iDuration;
+					$sSLTName = $oSLT->GetName();
+				}
 			}
-			if ($iDuration < $iMinDuration)
+			if ($iMinDuration == PHP_INT_MAX)
 			{
-				$iMinDuration = $iDuration;
-				$sSLTName = $oSLT->GetName();
+				$aResult = null;
+			}
+			else
+			{
+				array('SLT' => $sSLTName, 'value' => $iMinDuration);
 			}
 		}
-		if ($iMinDuration == PHP_INT_MAX) $iMinDuration = null;
-		return array('SLT' => $sSLTName, 'value' => $iMinDuration);
+		return $aResult;
 	}
 
-
-	public function ComputeValues()
+	/**
+	 * Compute the priority of the ticket based on its impact and urgency
+	 * @return integer The priority of the ticket 1(high) .. 3(low)
+	 */
+	public function ComputePriority()
 	{
-		$iKey = $this->GetKey();
-		if ($iKey < 0)
-		{
-			// Object not yet in the Database
-			$iKey = MetaModel::GetNextKey(get_class($this));
-		}
-		$sName = sprintf('I-%06d', $iKey);
-		$this->Set('ref', $sName);
-
 		// priority[impact][urgency]
 		$aPriorities = array(
 			// single person
 			1 => array(
-				1 => 1,
-				2 => 1,
-				3 => 2,
+					1 => 1,
+					2 => 1,
+					3 => 2,
 			),
 			// a group
 			2 => array(
@@ -388,25 +400,52 @@ class Incident extends Ticket
 			),
 			// a departement!
 			3 => array(
-				1 => 2,
-				2 => 3,
-				3 => 3,
+					1 => 2,
+					2 => 3,
+					3 => 3,
 			),
 		);
-		$iPriority = $aPriorities[$this->Get('impact')][$this->Get('urgency')];
-		$this->Set('priority', $iPriority);
+		$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
+		return $iPriority;		
+	}
+	
+	public function ComputeValues()
+	{
+		$iKey = $this->GetKey();
+		if ($iKey < 0)
+		{
+			// Object not yet in the Database
+			$iKey = MetaModel::GetNextKey(get_class($this));
+		}
+		$sName = sprintf('I-%06d', $iKey);
+		$this->Set('ref', $sName);
 		
-		// Compute the SLA deadlines
+		// Compute the priority of the ticket
+		$this->Set('priority', $this->ComputePriority());
 		
+		// Compute the SLA deadlines, if any is applicable to this ticket
 		$aSLT = $this->ComputeSLT('TTO');
-		$iStartDate = $this->Get('start_date');
-		//echo "<p>TTO: SLT found: {$aSLT['SLT']}, value: {$aSLT['value']}</p>\n";
-		$this->Set('escalation_deadline', $iStartDate + $aSLT['value']);
+		if ($aSLT != null)
+		{
+			//echo "<p>TTO: SLT found: {$aSLT['SLT']}, value: {$aSLT['value']}</p>\n";
+			$iStartDate = AttributeDateTime::GetAsUnixSeconds($this->Get('start_date'));		
+			$this->Set('escalation_deadline', $iStartDate + $aSLT['value']);
+		}
+		else
+		{
+			$this->Set('escalation_deadline', null);
+		}
 		$aSLT = $this->ComputeSLT('TTR');
-		//echo "<p>TTR: SLT found: {$aSLT['SLT']}, value: {$aSLT['value']}</p>\n";
-		$iStartDate = $this->Get('start_date');
-		$this->Set('closure_deadline', $iStartDate + $aSLT['value']);
-		
+		if ($aSLT != null)
+		{
+			//echo "<p>TTR: SLT found: {$aSLT['SLT']}, value: {$aSLT['value']}</p>\n";
+			$iStartDate = AttributeDateTime::GetAsUnixSeconds($this->Get('start_date'));		
+			$this->Set('closure_deadline', $iStartDate + $aSLT['value']);
+		}
+		else
+		{
+			$this->Set('closure_deadline', null);
+		}
 	}
 }
 class Change extends Ticket

+ 2 - 2
pages/UI.php

@@ -1342,7 +1342,7 @@ EOF
 	////MetaModel::ShowQueryTrace();
 	$oP->output();
 }
-catch(CoreException $e)
+catch(ZCoreException $e)
 {
 	require_once('../setup/setuppage.class.inc.php');
 	$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
@@ -1371,7 +1371,7 @@ catch(CoreException $e)
 	// For debugging only
 	//throw $e;
 }
-catch(Exception $e)
+catch(ZException $e)
 {
 	require_once('../setup/setuppage.class.inc.php');
 	$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));