فهرست منبع

New type of attribute: AttributeMetaEnum.
Designed to cope with the need to select tickets by operational status. The value of this attribute is computed by the framework. It depends on the actual ticket status (that attribute cannot be known by the root class because its definition varies from one type of ticket to another).
The data model has been enriched with the new attribute Ticket::operational_status. Its value is 'active' unless the ticket status is either 'rejected', 'resolved' or 'closed'. The existing dashboards have been left unchanged but should be revised to fully benefit from the new attribute (e.g. Open requests, Open problems, etc.)
Note: the alpha version of the compiler had already been committed by mistake a few days ago.

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3859 a333f486-631f-4898-b8df-5754b55c2be0

romainq 9 سال پیش
والد
کامیت
7f46108d88

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

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2015 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -21,7 +21,7 @@
  * Abstract class that implements some common and useful methods for displaying
  * the objects
  *
- * @copyright   Copyright (C) 2010-2015 Combodo SARL
+ * @copyright   Copyright (C) 2010-2016 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
@@ -2287,7 +2287,7 @@ EOF
 		$aDeps = array();
 		foreach($aDetailsList as $sAttCode)
 		{
-			$aDeps[$sAttCode] = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
+			$aDeps[$sAttCode] = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
 		}
 		$aList = self::OrderDependentFields($aDeps);
 		
@@ -2407,7 +2407,7 @@ EOF
 		$aDeps = array();
 		foreach($aAttributes as $sAttCode => $trash)
 		{
-			$aDeps[$sAttCode] = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
+			$aDeps[$sAttCode] = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
 		}
 		$aList = $this->OrderDependentFields($aDeps);
 
@@ -3489,7 +3489,7 @@ EOF
 			$sFormPrefix = '2_';
 			foreach($aList as $sAttCode => $oAttDef)
 			{
-				$aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
+				$aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
 				if (count($aPrerequisites) > 0)
 				{
 					// When 'enabling' a field, all its prerequisites must be enabled too

+ 122 - 9
core/attributedef.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2015 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -20,7 +20,7 @@
 /**
  * Typology for the attributes
  *
- * @copyright   Copyright (C) 2010-2015 Combodo SARL
+ * @copyright   Copyright (C) 2010-2016 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
@@ -353,7 +353,7 @@ abstract class AttributeDefinition
 	}
 
 	public function GetValuesDef() {return null;} 
-	public function GetPrerequisiteAttributes() {return array();} 
+	public function GetPrerequisiteAttributes($sClass = null) {return array();}
 
 	public function GetNullValue() {return null;} 
 	public function IsNull($proposedValue) {return is_null($proposedValue);} 
@@ -676,7 +676,7 @@ class AttributeLinkedSet extends AttributeDefinition
 	public function IsIndirect() {return false;} 
 
 	public function GetValuesDef() {return $this->Get("allowed_values");} 
-	public function GetPrerequisiteAttributes() {return $this->Get("depends_on");} 
+	public function GetPrerequisiteAttributes($sClass = null) {return $this->Get("depends_on");}
 	public function GetDefaultValue($aArgs = array())
 	{
 		// Note: so far, this feature is a prototype,
@@ -1274,7 +1274,7 @@ class AttributeDBFieldVoid extends AttributeDefinition
 	public function GetEditClass() {return "String";}
 	
 	public function GetValuesDef() {return $this->Get("allowed_values");} 
-	public function GetPrerequisiteAttributes() {return $this->Get("depends_on");} 
+	public function GetPrerequisiteAttributes($sClass = null) {return $this->Get("depends_on");}
 
 	public function IsDirectField() {return true;} 
 	public function IsScalar() {return true;} 
@@ -2993,6 +2993,120 @@ class AttributeEnum extends AttributeString
 }
 
 /**
+ * A meta enum is an aggregation of enum from subclasses into an enum of a base class
+ * It has been designed is to cope with the fact that statuses must be defined in leaf classes, while it makes sense to
+ * have a superstatus available on the root classe(s)
+ *
+ * @package     iTopORM
+ */
+class AttributeMetaEnum extends AttributeEnum
+{
+	static public function ListExpectedParams()
+	{
+		return array('allowed_values', 'sql', 'default_value', 'mapping');
+	}
+
+	public function IsWritable()
+	{
+		return false;
+	}
+
+	public function RequiresIndex()
+	{
+		return true;
+	}
+
+	public function GetPrerequisiteAttributes($sClass = null)
+	{
+		if (is_null($sClass))
+		{
+			$sClass = $this->GetHostClass();
+		}
+		$aMappingData = $this->GetMapRule($sClass);
+		if ($aMappingData == null)
+		{
+			$aRet = array();
+		}
+		else
+		{
+			$aRet = array($aMappingData['attcode']);
+		}
+		return $aRet;
+	}
+
+	/**
+	 * Overload the standard so as to leave the data unsorted
+	 *
+	 * @param array $aArgs
+	 * @param string $sContains
+	 * @return array|null
+	 */
+	public function GetAllowedValues($aArgs = array(), $sContains = '')
+	{
+		$oValSetDef = $this->GetValuesDef();
+		if (!$oValSetDef) return null;
+		$aRawValues = $oValSetDef->GetValueList();
+
+		if (is_null($aRawValues)) return null;
+		$aLocalizedValues = array();
+		foreach ($aRawValues as $sKey => $sValue)
+		{
+			$aLocalizedValues[$sKey] = Str::pure2html($this->GetValueLabel($sKey));
+		}
+		return $aLocalizedValues;
+	}
+
+	/**
+	 * Returns the meta value for the given object.
+	 * See also MetaModel::RebuildMetaEnums() that must be maintained when MapValue changes
+	 *
+	 * @param $oObject
+	 * @return mixed
+	 * @throws Exception
+	 */
+	public function MapValue($oObject)
+	{
+		$aMappingData = $this->GetMapRule(get_class($oObject));
+		if ($aMappingData == null)
+		{
+			$sRet = $this->GetDefaultValue();
+		}
+		else
+		{
+			$sAttCode = $aMappingData['attcode'];
+			$value = $oObject->Get($sAttCode);
+			if (array_key_exists($value, $aMappingData['values']))
+			{
+				$sRet = $aMappingData['values'][$value];
+			}
+			elseif ($this->GetDefaultValue() != '')
+			{
+				$sRet = $this->GetDefaultValue();
+			}
+			else
+			{
+				throw new Exception('AttributeMetaEnum::MapValue(): mapping not found for value "'.$value.'" in '.get_class($oObject).', on attribute '.MetaModel::GetAttributeOrigin($this->GetHostClass(), $this->GetCode()).'::'.$this->GetCode());
+			}
+		}
+		return $sRet;
+	}
+
+	public function GetMapRule($sClass)
+	{
+		$aMappings = $this->Get('mapping');
+		if (array_key_exists($sClass, $aMappings))
+		{
+			$aMappingData = $aMappings[$sClass];
+		}
+		else
+		{
+			$sParent = MetaModel::GetParentClass($sClass);
+			$aMappingData = $this->GetMapRule($sParent);
+		}
+		return $aMappingData;
+	}
+}
+/**
  * Map a date+time column to an attribute 
  *
  * @package     iTopORM
@@ -3794,7 +3908,7 @@ class AttributeExternalField extends AttributeDefinition
 		}
 	}
 	
-	public function GetPrerequisiteAttributes()
+	public function GetPrerequisiteAttributes($sClass = null)
 	{
 		return array($this->Get("extkey_attcode"));
 	} 
@@ -4833,7 +4947,6 @@ class AttributeSubItem extends AttributeDefinition
 	public function GetEditClass() {return "";}
 	
 	public function GetValuesDef() {return null;} 
-	//public function GetPrerequisiteAttributes() {return $this->Get("depends_on");} 
 
 	public function IsDirectField() {return true;} 
 	public function IsScalar() {return true;} 
@@ -5322,7 +5435,7 @@ class AttributeComputedFieldVoid extends AttributeDefinition
 	public function GetEditClass() {return "";}
 	
 	public function GetValuesDef() {return null;} 
-	public function GetPrerequisiteAttributes() {return $this->GetOptional("depends_on", array());} 
+	public function GetPrerequisiteAttributes($sClass = null) {return $this->GetOptional("depends_on", array());}
 
 	public function IsDirectField() {return true;} 
 	public function IsScalar() {return true;} 
@@ -5546,7 +5659,7 @@ class AttributeRedundancySettings extends AttributeDBField
 	}
 
 	public function GetValuesDef() {return null;} 
-	public function GetPrerequisiteAttributes() {return array();} 
+	public function GetPrerequisiteAttributes($sClass = null) {return array();}
 
 	public function GetEditClass() {return "RedundancySetting";}
 	protected function GetSQLCol($bFullSpec = false)

+ 8 - 3
core/dbobject.class.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2015 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -52,7 +52,7 @@ interface iDisplay
 /**
  * Class dbObject: the root of persistent classes
  *
- * @copyright   Copyright (C) 2010-2015 Combodo SARL
+ * @copyright   Copyright (C) 2010-2016 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
@@ -412,7 +412,12 @@ abstract class DBObject implements iDisplay
 		$this->m_aCurrValues[$sAttCode] = $realvalue;
 		$this->m_aTouchedAtt[$sAttCode] = true;
 		unset($this->m_aModifiedAtt[$sAttCode]);
-		
+
+		foreach (MetaModel::ListMetaAttributes(get_class($this), $sAttCode) as $sMetaAttCode => $oMetaAttDef)
+		{
+			$this->Set($sMetaAttCode, $oMetaAttDef->MapValue($this));
+		}
+
 		// The object has changed, reset caches
 		$this->m_bCheckStatus = null;
 

+ 101 - 7
core/metamodel.class.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2015 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -26,7 +26,7 @@ require_once(APPROOT.'core/relationgraph.class.inc.php');
 /**
  * Metamodel
  *
- * @copyright   Copyright (C) 2010-2015 Combodo SARL
+ * @copyright   Copyright (C) 2010-2016 Combodo SARL
  * @license     http://opensource.org/licenses/AGPL-3.0
  */
 
@@ -487,7 +487,7 @@ abstract class MetaModel
 		self::_check_subclass($sClass);
 		return self::$m_aAttribOrigins[$sClass][$sAttCode];
 	}
-	final static public function GetPrequisiteAttributes($sClass, $sAttCode)
+	final static public function GetPrerequisiteAttributes($sClass, $sAttCode)
 	{
 		self::_check_subclass($sClass);
 		$oAtt = self::GetAttributeDef($sClass, $sAttCode);
@@ -499,7 +499,7 @@ abstract class MetaModel
 		return $oAtt->GetPrerequisiteAttributes();
 	}
 	/**
-	 * Find all attributes that depend on the specified one (reverse of GetPrequisiteAttributes)
+	 * Find all attributes that depend on the specified one (reverse of GetPrerequisiteAttributes)
 	 * @param string $sClass Name of the class
 	 * @param string $sAttCode Code of the attributes
 	 * @return Array List of attribute codes that depend on the given attribute, empty array if none.
@@ -510,7 +510,7 @@ abstract class MetaModel
 		self::_check_subclass($sClass);
 		foreach (self::ListAttributeDefs($sClass) as $sDependentAttCode=>$void)
 		{
-			$aPrerequisites = self::GetPrequisiteAttributes($sClass, $sDependentAttCode);
+			$aPrerequisites = self::GetPrerequisiteAttributes($sClass, $sDependentAttCode);
 			if (in_array($sAttCode, $aPrerequisites))
 			{
 				$aResults[] = $sDependentAttCode;
@@ -633,7 +633,8 @@ abstract class MetaModel
 	private static $m_aAttribDefs = array(); // array of ("classname" => array of attributes)
 	private static $m_aAttribOrigins = array(); // array of ("classname" => array of ("attcode"=>"sourceclass"))
 	private static $m_aExtKeyFriends = array(); // array of ("classname" => array of ("indirect ext key attcode"=> array of ("relative ext field")))
-	private static $m_aIgnoredAttributes = array(); //array of ("classname" => array of ("attcode")
+	private static $m_aIgnoredAttributes = array(); //array of ("classname" => array of ("attcode"))
+	private static $m_aEnumToMeta = array(); // array of  ("classname" => array of ("attcode" => array of ("metaattcode" => oMetaAttDef))
 
 	final static public function ListAttributeDefs($sClass)
 	{
@@ -848,6 +849,18 @@ abstract class MetaModel
 		return self::$m_aTrackForwardCache[$sClass];
 	}
 
+	final static public function ListMetaAttributes($sClass, $sAttCode)
+	{
+		if (isset(self::$m_aEnumToMeta[$sClass][$sAttCode]))
+		{
+			$aRet = self::$m_aEnumToMeta[$sClass][$sAttCode];
+		}
+		else
+		{
+			$aRet = array();
+		}
+		return $aRet;
+	}
 
 	/**
 	 * Get the attribute label
@@ -1847,6 +1860,15 @@ abstract class MetaModel
 						}
 					}
 				}
+				if ($oAttDef instanceof AttributeMetaEnum)
+				{
+					$aMappingData = $oAttDef->GetMapRule($sClass);
+					if ($aMappingData != null)
+					{
+						$sEnumAttCode = $aMappingData['attcode'];
+						self::$m_aEnumToMeta[$sClass][$sEnumAttCode][$sAttCode] = $oAttDef;
+					}
+				}
 			}
 
 			// Add a 'id' filter
@@ -2685,7 +2707,77 @@ abstract class MetaModel
 			CMDBSource::Query($sSQL);
 		}
 	}
-	
+
+	/**
+	 * Update the meta enums
+	 * See Also AttributeMetaEnum::MapValue that must be aligned with the above implementation
+	 *
+	 * @param $bVerbose boolean Displays some information about what is done/what needs to be done
+	 */
+	public static function RebuildMetaEnums($bVerbose = false)
+	{
+		foreach (self::GetClasses() as $sClass)
+		{
+			if (!self::HasTable($sClass)) continue;
+
+			foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
+			{
+				// Check (once) all the attributes that are hierarchical keys
+				if((self::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef instanceof AttributeEnum)
+				{
+					if (isset(self::$m_aEnumToMeta[$sClass][$sAttCode]))
+					{
+						foreach (self::$m_aEnumToMeta[$sClass][$sAttCode] as $sMetaAttCode => $oMetaAttDef)
+						{
+							$aMetaValues = array(); // array of (metavalue => array of values)
+							foreach ($oAttDef->GetAllowedValues() as $sCode => $sLabel)
+							{
+								$aMappingData = $oMetaAttDef->GetMapRule($sClass);
+								if ($aMappingData == null)
+								{
+									$sMetaValue = $oMetaAttDef->GetDefaultValue();
+								}
+								else
+								{
+									if (array_key_exists($sCode, $aMappingData['values']))
+									{
+										$sMetaValue = $aMappingData['values'][$sCode];
+									}
+									elseif ($oMetaAttDef->GetDefaultValue() != '')
+									{
+										$sMetaValue = $oMetaAttDef->GetDefaultValue();
+									}
+									else
+									{
+										throw new Exception('MetaModel::RebuildMetaEnums(): mapping not found for value "'.$sCode.'"" in '.$sClass.', on attribute '.self::GetAttributeOrigin($sClass, $oMetaAttDef->GetCode()).'::'.$oMetaAttDef->GetCode());
+									}
+								}
+								$aMetaValues[$sMetaValue][] = $sCode;
+							}
+							foreach ($aMetaValues as $sMetaValue => $aEnumValues)
+							{
+								$sMetaTable = self::DBGetTable($sClass, $sMetaAttCode);
+								$sEnumTable = self::DBGetTable($sClass);
+								$aColumns = array_keys($oMetaAttDef->GetSQLColumns());
+								$sMetaColumn = reset($aColumns);
+								$aColumns = array_keys($oAttDef->GetSQLColumns());
+								$sEnumColumn = reset($aColumns);
+								$sValueList = implode(', ', CMDBSource::Quote($aEnumValues));
+								$sSql = "UPDATE `$sMetaTable` JOIN `$sEnumTable` ON `$sEnumTable`.id = `$sMetaTable`.id SET `$sMetaTable`.`$sMetaColumn` = '$sMetaValue' WHERE `$sEnumTable`.`$sEnumColumn` IN ($sValueList) AND `$sMetaTable`.`$sMetaColumn` != '$sMetaValue'";
+								if ($bVerbose)
+								{
+									echo "Executing query: $sSql\n";
+								}
+								CMDBSource::Query($sSql);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+
 	public static function CheckDataSources($bDiagnostics, $bVerbose)
 	{
 		$sOQL = 'SELECT SynchroDataSource';
@@ -4190,6 +4282,7 @@ abstract class MetaModel
 				self::$m_aStimuli = $result['m_aStimuli'];
 				self::$m_aTransitions = $result['m_aTransitions'];
 				self::$m_aHighlightScales = $result['m_aHighlightScales'];
+				self::$m_aEnumToMeta = $result['m_aEnumToMeta'];
 			}
 			$oKPI->ComputeAndReport('Metamodel APC (fetch + read)');
 		}
@@ -4227,6 +4320,7 @@ abstract class MetaModel
 				$aCache['m_aStimuli'] = self::$m_aStimuli; // array of ("classname" => array of ("stimuluscode"=>array('label'=>...)))
 				$aCache['m_aTransitions'] = self::$m_aTransitions; // array of ("classname" => array of ("statcode_from"=>array of ("stimuluscode" => array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD)))
 				$aCache['m_aHighlightScales'] = self::$m_aHighlightScales; // array of ("classname" => array of higlightcodes)))
+				$aCache['m_aEnumToMeta'] = self::$m_aEnumToMeta;
 				apc_store($sOqlAPCCacheId, $aCache);
 				$oKPI->ComputeAndReport('Metamodel APC (store)');
 			}

+ 30 - 0
datamodels/2.x/itop-change-mgmt-itil/datamodel.itop-change-mgmt-itil.xml

@@ -1103,6 +1103,9 @@
             <item id="status">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="title">
               <rank>40</rank>
             </item>
@@ -1179,6 +1182,9 @@
             <item id="status">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="agent_id">
               <rank>70</rank>
             </item>
@@ -1893,6 +1899,9 @@
             <item id="status">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="title">
               <rank>40</rank>
             </item>
@@ -1969,6 +1978,9 @@
             <item id="status">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="agent_id">
               <rank>70</rank>
             </item>
@@ -2884,6 +2896,9 @@
             <item id="status">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="title">
               <rank>40</rank>
             </item>
@@ -2963,6 +2978,9 @@
             <item id="status">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="agent_id">
               <rank>70</rank>
             </item>
@@ -3570,6 +3588,9 @@
             <item id="status">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="title">
               <rank>40</rank>
             </item>
@@ -3652,6 +3673,9 @@
             <item id="status">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="agent_id">
               <rank>70</rank>
             </item>
@@ -4323,6 +4347,9 @@
             <item id="status">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="title">
               <rank>40</rank>
             </item>
@@ -4402,6 +4429,9 @@
             <item id="status">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="agent_id">
               <rank>70</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-change-mgmt/datamodel.itop-change-mgmt.xml

@@ -664,6 +664,9 @@
             <item id="status">
               <rank>40</rank>
             </item>
+            <item id="operational_status">
+              <rank>45</rank>
+            </item>
             <item id="start_date">
               <rank>50</rank>
             </item>
@@ -707,6 +710,9 @@
             <item id="status">
               <rank>50</rank>
             </item>
+            <item id="operational_status">
+              <rank>55</rank>
+            </item>
             <item id="category">
               <rank>60</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-incident-mgmt-itil/datamodel.itop-incident-mgmt-itil.xml

@@ -1553,6 +1553,9 @@
             <item id="status">
               <rank>90</rank>
             </item>
+            <item id="operational_status">
+              <rank>95</rank>
+            </item>
             <item id="caller_id">
               <rank>100</rank>
             </item>
@@ -1614,6 +1617,9 @@
             <item id="status">
               <rank>50</rank>
             </item>
+            <item id="operational_status">
+              <rank>55</rank>
+            </item>
             <item id="agent_id">
               <rank>60</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-problem-mgmt/datamodel.itop-problem-mgmt.xml

@@ -607,6 +607,9 @@
             <item id="status">
               <rank>50</rank>
             </item>
+            <item id="operational_status">
+              <rank>55</rank>
+            </item>
             <item id="service_id">
               <rank>60</rank>
             </item>
@@ -653,6 +656,9 @@
             <item id="status">
               <rank>40</rank>
             </item>
+            <item id="operational_status">
+              <rank>45</rank>
+            </item>
             <item id="service_id">
               <rank>50</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-request-mgmt-itil/datamodel.itop-request-mgmt-itil.xml

@@ -1615,6 +1615,9 @@
             <item id="status">
               <rank>90</rank>
             </item>
+            <item id="operational_status">
+              <rank>95</rank>
+            </item>
             <item id="caller_id">
               <rank>100</rank>
             </item>
@@ -1679,6 +1682,9 @@
             <item id="status">
               <rank>50</rank>
             </item>
+            <item id="operational_status">
+              <rank>55</rank>
+            </item>
             <item id="agent_id">
               <rank>60</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-request-mgmt/datamodel.itop-request-mgmt.xml

@@ -1615,6 +1615,9 @@
             <item id="status">
               <rank>90</rank>
             </item>
+            <item id="operational_status">
+              <rank>95</rank>
+            </item>
             <item id="caller_id">
               <rank>100</rank>
             </item>
@@ -1679,6 +1682,9 @@
             <item id="status">
               <rank>50</rank>
             </item>
+            <item id="operational_status">
+              <rank>55</rank>
+            </item>
             <item id="agent_id">
               <rank>60</rank>
             </item>

+ 32 - 1
datamodels/2.x/itop-tickets/datamodel.itop-tickets.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.2">
+<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.3">
   <constants>
     <constant id="RESPONSE_TICKET_SLT_QUERY" xsi:type="string" _delta="define"><![CDATA[SELECT SLT AS slt JOIN lnkSLAToSLT AS l1 ON l1.slt_id=slt.id JOIN SLA AS sla ON l1.sla_id=sla.id JOIN lnkCustomerContractToService AS l2 ON l2.sla_id=sla.id JOIN CustomerContract AS sc ON l2.customercontract_id=sc.id WHERE slt.metric = :metric AND l2.service_id = :this->service_id AND sc.org_id = :this->org_id AND slt.request_type = :request_type AND slt.priority = :this->priority]]></constant>
     <constant id="PORTAL_POWER_USER_PROFILE" xsi:type="string" _delta="define"><![CDATA[Portal power user]]></constant>
@@ -45,6 +45,28 @@
         </reconciliation>
       </properties>
       <fields>
+        <field id="operational_status" xsi:type="AttributeMetaEnum">
+          <values>
+            <value id="active">active</value>
+            <value id="inactive">inactive</value>
+          </values>
+          <sql>operational_status</sql>
+          <default_value>active</default_value>
+          <mappings>
+            <mapping id="Ticket">
+              <attcode>status</attcode>
+              <metavalues>
+                <metavalue id="inactive">
+                  <values>
+                    <value id="resolved"/>
+                    <value id="closed"/>
+                    <value id="rejected"/>
+                  </values>
+                </metavalue>
+              </metavalues>
+            </mapping>
+          </mappings>
+        </field>
         <field id="ref" xsi:type="AttributeString">
           <sql>ref</sql>
           <default_value/>
@@ -238,6 +260,9 @@
             <item id="description">
               <rank>70</rank>
             </item>
+            <item id="operational_status">
+              <rank>75</rank>
+            </item>
             <item id="start_date">
               <rank>80</rank>
             </item>
@@ -275,6 +300,9 @@
             <item id="description">
               <rank>30</rank>
             </item>
+            <item id="operational_status">
+              <rank>35</rank>
+            </item>
             <item id="start_date">
               <rank>40</rank>
             </item>
@@ -309,6 +337,9 @@
             <item id="agent_id">
               <rank>60</rank>
             </item>
+            <item id="operational_status">
+              <rank>65</rank>
+            </item>
             <item id="start_date">
               <rank>70</rank>
             </item>

+ 6 - 0
datamodels/2.x/itop-tickets/en.dict.itop-tickets.php

@@ -82,6 +82,12 @@ Dict::Add('EN US', 'English', 'English', array(
 	'Class:Ticket/Attribute:workorders_list+' => 'All the work orders for this ticket',
 	'Class:Ticket/Attribute:finalclass' => 'Type',
 	'Class:Ticket/Attribute:finalclass+' => '',
+	'Class:Ticket/Attribute:operational_status' => 'Operational status',
+	'Class:Ticket/Attribute:operational_status+' => 'Computed after the detailed status',
+	'Class:Ticket/Attribute:operational_status/Value:active' => 'Active',
+	'Class:Ticket/Attribute:operational_status/Value:active+' => 'Work in progress',
+	'Class:Ticket/Attribute:operational_status/Value:inactive' => 'Inactive',
+	'Class:Ticket/Attribute:operational_status/Value:inactive+' => 'Done',
 	'Ticket:ImpactAnalysis' => 'Impact Analysis',
 ));
 

+ 6 - 0
datamodels/2.x/itop-tickets/fr.dict.itop-tickets.php

@@ -69,6 +69,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
 	'Class:Ticket/Attribute:workorders_list+' => '',
 	'Class:Ticket/Attribute:finalclass' => 'Type',
 	'Class:Ticket/Attribute:finalclass+' => '',
+	'Class:Ticket/Attribute:operational_status' => 'Statut opérationnel',
+	'Class:Ticket/Attribute:operational_status+' => 'Calculé à partir du statut détaillé',
+	'Class:Ticket/Attribute:operational_status/Value:active' => 'Actif',
+	'Class:Ticket/Attribute:operational_status/Value:active+' => 'Traitement en cours',
+	'Class:Ticket/Attribute:operational_status/Value:inactive' => 'Inactif',
+	'Class:Ticket/Attribute:operational_status/Value:inactive+' => 'Ticket définitivement fermé',
 	'Ticket:ImpactAnalysis' => 'Analyse d\'Impact',
 ));
 

+ 2 - 2
pages/UI.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2010-2015 Combodo SARL
+// Copyright (C) 2010-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -1071,7 +1071,7 @@ EOF
 				{
 					$aAttributesDef = MetaModel::ListAttributeDefs($sClass);
 					$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
-					$aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
+					$aPrerequisites = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one
 					if (count($aPrerequisites) > 0)
 					{
 						// When 'enabling' a field, all its prerequisites must be enabled too

+ 1 - 5
setup/compiler.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2011-2015 Combodo SARL
+// Copyright (C) 2011-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -1096,13 +1096,9 @@ EOF;
 					}
 					//	new style... $sValues = 'array('.implode(', ', $aValues).')';
 					$sValues = '"'.implode(',', $aValues).'"';
-// todo: enlever les paramètres inutiles = display_style, depends on, default_value, is_null_allowed ???
 					$aParameters['allowed_values'] = "new ValueSetEnum($sValues)";
-					$aParameters['display_style'] = $this->GetPropString($oField, 'display_style', 'list');
 					$aParameters['sql'] = $this->GetMandatoryPropString($oField, 'sql', '');
 					$aParameters['default_value'] = $this->GetPropString($oField, 'default_value', '');
-					$aParameters['is_null_allowed'] = $this->GetPropBoolean($oField, 'is_null_allowed', false);
-					$aParameters['depends_on'] = $sDependencies;
 
 					$oMappings = $oField->GetUniqueElement('mappings');
 					$oMappingNodes = $oMappings->getElementsByTagName('mapping');

+ 10 - 1
setup/itopdesignformat.class.inc.php

@@ -1,5 +1,5 @@
 <?php
-// Copyright (C) 2014-2015 Combodo SARL
+// Copyright (C) 2014-2016 Combodo SARL
 //
 //   This file is part of iTop.
 //
@@ -501,6 +501,15 @@ class iTopDesignFormat
 			$this->LogWarning('The module design defined in '.self::GetItopNodePath($oNode).' will be lost.');
 			$this->DeleteNode($oNode);
 		}
+
+		// Remove MetaEnum attributes
+		//
+		$oNodeList = $oXPath->query("/itop_design/classes//class/fields/field[@xsi:type='AttributeMetaEnum']");
+		foreach ($oNodeList as $oNode)
+		{
+			$this->LogWarning('The attribute '.self::GetItopNodePath($oNode).' is irrelevant and must be removed.');
+			$this->DeleteNode($oNode);
+		}
 	}
 
 	/**