Тикет управления конфигурациями

Можно попробовать более простой вариант. Если автоматический анализ влияние и привязка КЕ не нужны, их можно попробовать отключить.

В вашем модуле с классом RoutineChange переопределите methods, скопировав содержимое из класса Сhange, но удалив из OnInsert() и из OnUpdate() вызов UpdateImpactedItems().

Impact Analisys нужен.

В методах класса Ticket, представлены два метода DBInsertNo Reload и MakeTicketRef, я не вижу здесь что-то подобное формированию перечня линков lnkFunctionalCIToTicket.

я скопировал весь класс Ticket в свой модуль, и сделал redefine всему блоку methods, и на этом остановился

Перестаньте копировать всё подряд. В свой модуль вносите только изменения относительно стандартной модели данных.

Код метода тут UpdateImpactedItems(): main.itop-tickets.php.
Класс Ticket тут: datamodel.itop-tickets.xml.

В своем модуле для класса Ticket аналогично представленным в нём методам делаете новый метод UpdateImpactedItems, куда вставляете код из main.itop-tickets.php. Затем этот код редактируете.

Сократил код. Определил новый метод:

<class id="Ticket">
  <fields>
    <field id="description" xsi:type="AttributeText" _delta="redefine">
      <sql>description</sql>
      <default_value/>
      <is_null_allowed>true</is_null_allowed>
    </field>
  </fields>
  <methods>
    <method id="UpdateImpactedItems" _delta="define">
    </method>
  </methods>
</class>

Теперь между тэгами методам, нужно вставить весь код?:

public function UpdateImpactedItems()
	{
		require_once(APPROOT.'core/displayablegraph.class.inc.php');
		$oContactsSet = $this->Get('contacts_list');
		$oCIsSet = $this->Get('functionalcis_list');

		$aCIsToImpactCode = array();
		$aSources = array();
		$aExcluded = array();
		
		$oCIsSet->Rewind();
		while ($oLink = $oCIsSet->Fetch())
		{
			$iKey = $oLink->Get('functionalci_id');
			$aCIsToImpactCode[$iKey] = $oLink->Get('impact_code');
			if ($oLink->Get('impact_code') == 'manual')
			{
				$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
				$aSources[$iKey] = $oObj;
			}
			else if ($oLink->Get('impact_code') == 'not_impacted')
			{
				$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
				$aExcluded[$iKey] = $oObj;
			}
		}
		
		$aContactsToRoleCode = array();
		$oContactsSet->Rewind();
		while ($oLink = $oContactsSet->Fetch())
		{
			$iKey = $oLink->Get('contact_id');
			$aContactsToRoleCode[$iKey] = $oLink->Get('role_code');
			if ($oLink->Get('role_code') == 'do_not_notify')
			{
				$oObj = MetaModel::GetObject('Contact', $iKey);
				$aExcluded[$iKey] = $oObj;
			}
		}
		
		$oNewCIsSet = DBObjectSet::FromScratch('lnkFunctionalCIToTicket');
		foreach($aCIsToImpactCode as $iKey => $sImpactCode)
		{
			if ($sImpactCode != 'computed')
			{
				$oNewLink = new lnkFunctionalCIToTicket();
				$oNewLink->Set('functionalci_id', $iKey);
				$oNewLink->Set('impact_code', $sImpactCode);
				$oNewCIsSet->AddObject($oNewLink);				
			}
		}
		
		$oNewContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
		foreach($aContactsToRoleCode as $iKey => $sImpactCode)
		{
			if ($sImpactCode != 'computed')
			{
				$oNewLink = new lnkContactToTicket();
				$oNewLink->Set('contact_id', $iKey);
				$oNewLink->Set('role_code', $sImpactCode);
				$oNewContactsSet->AddObject($oNewLink);
			}
		}
		
		$oContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
		
		$sContextKey = 'itop-tickets/relation_context/'.get_class($this).'/impacts/down';
		$aContextDefs = DisplayableGraph::GetContextDefinitions($sContextKey, true, array('this' => $this));
		$aDefaultContexts = array();
		foreach($aContextDefs as $sKey => $aDefinition)
		{
			// Add the default context queries to the computation
			if (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes'))
			{
				$aDefaultContexts[] = $aDefinition['oql'];
			}
		}
		// Merge the directly impacted items with the "new" ones added by the "context" queries
		$aGraphObjects = array();
		$oRawGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded);
		$oIterator = new RelationTypeIterator($oRawGraph, 'Node');
		foreach ($oIterator as $oNode)
		{
			// Any object node reached AND different from a source will do
			if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) )
			{
				$oObj = $oNode->GetProperty('object');
				$iKey = $oObj->GetKey();
				$sRootClass = MetaModel::GetRootClass(get_class($oObj));
				$aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
			}
		}
		
		if (count($aDefaultContexts) > 0)
		{
			$oAnnotatedGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded, $aDefaultContexts);
			$oIterator = new RelationTypeIterator($oAnnotatedGraph, 'Node');
			foreach ($oIterator as $oNode)
			{
				// Only pick the nodes which are NOT impacted by a context root cause, and merge them in the list
				if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) && ($oNode->GetProperty('context_root_causes', null) == null) )
				{
					$oObj = $oNode->GetProperty('object');
					$iKey = $oObj->GetKey();
					$sRootClass = MetaModel::GetRootClass(get_class($oObj));
					$aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
				}
			}
		}
		
		foreach ($aGraphObjects as $oObj)
		{
			$iKey = $oObj->GetKey();
			$sRootClass = MetaModel::GetRootClass(get_class($oObj));
			switch ($sRootClass)
			{
				case 'FunctionalCI':		
				// Only link FunctionalCIs which are not already linked to the ticket
				if (!array_key_exists($iKey, $aCIsToImpactCode) || ($aCIsToImpactCode[$iKey] != 'not_impacted'))
				{
					$oNewLink = new lnkFunctionalCIToTicket();
					$oNewLink->Set('functionalci_id', $iKey);
					$oNewLink->Set('impact_code', 'computed');
					$oNewCIsSet->AddObject($oNewLink);
				}
				break;
				
				case 'Contact':
				// Only link Contacts which are not already linked to the ticket
				if (!array_key_exists($iKey, $aContactsToRoleCode) || ($aCIsToImpactCode[$iKey] != 'do_not_notify'))
				{
					$oNewLink = new lnkContactToTicket();
					$oNewLink->Set('contact_id', $iKey);
					$oNewLink->Set('role_code', 'computed');
					$oNewContactsSet->AddObject($oNewLink);
				}
				break;
			}
		}
		$this->Set('functionalcis_list', $oNewCIsSet);
		$this->Set('contacts_list', $oNewContactsSet);
	}

Как в нем правильно определить значения поля action_code?

Да, только посмотрите, как оформлены методы в стандартных моделях.

Нужно разобрать как работает код, а потом куда-то воткнуть что-то типа $oNewLink->Set('action_code', $sActionCode);, где переменная $sActionCode должна содержать одно из ваших значений.

После того, как я определил новый метод, и вставил в него весь код из main, toolkit выдает вот такое сообщение:

File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:154 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:154 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:164 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:164 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:164 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:164 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name
File: /var/www/itop/TEST/extensions/action-ticket/datamodel.action-ticket.xml Line:179 Message:xmlParseEntityRef: no name 

Но пишет что все ОК - Это нормально?

@vladimir помогите пожалуйста разобраться с кодом, я его не понимаю(…я вставил $oNewLink->Set(‘action_code’, $sActionCode); во все условия этой функции, но безрезультатно

Нет.

ЧТобы разобраться с кодом, нужно немного разобраться с php. iTop заканчивается на xml-модели данных.

Вот ваш метод:

    <method id="UpdateImpactedItems" _delta="define">
      <static>false</static>
      <access>protected</access>
      <type>Overload-DBObject</type>
      <code><![CDATA[public function UpdateImpactedItems()
{
  require_once(APPROOT.'core/displayablegraph.class.inc.php');
  $oContactsSet = $this->Get('contacts_list');
  $oCIsSet = $this->Get('functionalcis_list');

  $aCIsToImpactCode = array();
  $aSources = array();
  $aExcluded = array();

  $oCIsSet->Rewind();
  while ($oLink = $oCIsSet->Fetch())
  {
    $iKey = $oLink->Get('functionalci_id');
    $aCIsToImpactCode[$iKey] = $oLink->Get('impact_code');
    $aCIsToActionCode[$iKey] = $oLink->Get('action_code');
    if ($oLink->Get('impact_code') == 'manual')
    {
      $oObj = MetaModel::GetObject('FunctionalCI', $iKey);
      $aSources[$iKey] = $oObj;
    }
    else if ($oLink->Get('impact_code') == 'not_impacted')
    {
      $oObj = MetaModel::GetObject('FunctionalCI', $iKey);
      $aExcluded[$iKey] = $oObj;
    }
  }

  $aContactsToRoleCode = array();
  $oContactsSet->Rewind();
  while ($oLink = $oContactsSet->Fetch())
  {
    $iKey = $oLink->Get('contact_id');
    $aContactsToRoleCode[$iKey] = $oLink->Get('role_code');
    if ($oLink->Get('role_code') == 'do_not_notify')
    {
      $oObj = MetaModel::GetObject('Contact', $iKey);
      $aExcluded[$iKey] = $oObj;
    }
  }

  $oNewCIsSet = DBObjectSet::FromScratch('lnkFunctionalCIToTicket');
  foreach($aCIsToImpactCode as $iKey => $sImpactCode)
  {
    if ($sImpactCode != 'computed')
    {
      $oNewLink = new lnkFunctionalCIToTicket();
      $oNewLink->Set('functionalci_id', $iKey);
      $oNewLink->Set('impact_code', $sImpactCode);
      $oNewLink->Set('action_code', $aCIsToActionCode[$iKey]);
      $oNewCIsSet->AddObject($oNewLink);
    }
  }

  $oNewContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
  foreach($aContactsToRoleCode as $iKey => $sImpactCode)
  {
    if ($sImpactCode != 'computed')
    {
      $oNewLink = new lnkContactToTicket();
      $oNewLink->Set('contact_id', $iKey);
      $oNewLink->Set('role_code', $sImpactCode);
      $oNewContactsSet->AddObject($oNewLink);
    }
  }

  $oContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');

  $sContextKey = 'itop-tickets/relation_context/'.get_class($this).'/impacts/down';
  $aContextDefs = DisplayableGraph::GetContextDefinitions($sContextKey, true, array('this' => $this));
  $aDefaultContexts = array();
  foreach($aContextDefs as $sKey => $aDefinition)
  {
    // Add the default context queries to the computation
    if (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes'))
    {
      $aDefaultContexts[] = $aDefinition['oql'];
    }
  }
  // Merge the directly impacted items with the "new" ones added by the "context" queries
  $aGraphObjects = array();
  $oRawGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded);
  $oIterator = new RelationTypeIterator($oRawGraph, 'Node');
  foreach ($oIterator as $oNode)
  {
    // Any object node reached AND different from a source will do
    if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) )
    {
      $oObj = $oNode->GetProperty('object');
      $iKey = $oObj->GetKey();
      $sRootClass = MetaModel::GetRootClass(get_class($oObj));
      $aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
    }
  }

  if (count($aDefaultContexts) > 0)
  {
    $oAnnotatedGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded, $aDefaultContexts);
    $oIterator = new RelationTypeIterator($oAnnotatedGraph, 'Node');
    foreach ($oIterator as $oNode)
    {
      // Only pick the nodes which are NOT impacted by a context root cause, and merge them in the list
      if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')) && ($oNode->GetProperty('context_root_causes', null) == null) )
      {
        $oObj = $oNode->GetProperty('object');
        $iKey = $oObj->GetKey();
        $sRootClass = MetaModel::GetRootClass(get_class($oObj));
        $aGraphObjects[get_class($oObj).'::'.$iKey] = $oNode->GetProperty('object');
      }
    }
  }

  foreach ($aGraphObjects as $oObj)
  {
    $iKey = $oObj->GetKey();
    $sRootClass = MetaModel::GetRootClass(get_class($oObj));
    switch ($sRootClass)
    {
      case 'FunctionalCI':
      // Only link FunctionalCIs which are not already linked to the ticket
      if (!array_key_exists($iKey, $aCIsToImpactCode) || ($aCIsToImpactCode[$iKey] != 'not_impacted'))
      {
        $oNewLink = new lnkFunctionalCIToTicket();
        $oNewLink->Set('functionalci_id', $iKey);
        $oNewLink->Set('impact_code', 'computed');
        $oNewCIsSet->AddObject($oNewLink);
      }
      break;

      case 'Contact':
      // Only link Contacts which are not already linked to the ticket
      if (!array_key_exists($iKey, $aContactsToRoleCode) || ($aCIsToImpactCode[$iKey] != 'do_not_notify'))
      {
        $oNewLink = new lnkContactToTicket();
        $oNewLink->Set('contact_id', $iKey);
        $oNewLink->Set('role_code', 'computed');
        $oNewContactsSet->AddObject($oNewLink);
      }
      break;
    }
  }
  $this->Set('functionalcis_list', $oNewCIsSet);
  $this->Set('contacts_list', $oNewContactsSet);
}]]></code>
    </method>

Ситуация с добавлением метода не изменилась, так и сбрасывается в “неопределен” (

Значит вы где-то ошиблись.

@vladimir Спасибо огромное! работает! оказывается дело в условие. если добавлен вручную, то применяется указанное действие, если нет, то выставляется неопределен…а я то думал…

осталось последнее действие - это добавить кнопку “создать КЕ” в форме поиска КЕ

подскажите пожалуйста в каком файле и как это сделать?

Во вкладке сохраняется то, что добавлено в ручную или не влияет. Остальное пересчитывается при сохранении тикета.

Быстро — никак. Нужно ковырять код.

Получилось вот так:

добавил

$sHtml .= "<p align=\"right\"><a href=\"UI.php?operation=new&class=FunctionalCI&c%5Bmenu%5D=NewCI\" target=\"_blank\">Create CI</a></p>\n";

в файл application/cmdbabstract.class.inc.php

Если вас это устраивает, то можно и так конечно)

Пока устраивает, главное что она есть :smile:

2 сообщений перенесены в уже существующую тему: Модуль “Управления Изменениями”

Товарищи, чтоб создать простую форму “Создано-закрыто” или “создано-в работе-закрыто” для тикетов хелпдеска нужно тоже создавать свой модуль? или может есть готовый где ?

Если создавать свой, подскажите что копировать из itop-request-mgmt?

  1. Чтобы случайно не разрушить структуру itop, все изменения выполняются через собственный модуль.
  2. Создаете свой модуль, копируете блок переходов стимулис) данного класса, и правите переходы, как писал @vladimir вот здесь Тикет управления конфигурациями