mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-01 21:52:17 +02:00
Compare commits
7 Commits
feature/95
...
feature/91
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5355c71a2c | ||
|
|
df4e9ba246 | ||
|
|
86b401591f | ||
|
|
6bd31230e1 | ||
|
|
d7ef9acf1a | ||
|
|
09ea64e5d5 | ||
|
|
2c44edbe66 |
@@ -460,6 +460,18 @@
|
||||
<extkey_attcode>parent_incident_id</extkey_attcode>
|
||||
<target_attcode>ref</target_attcode>
|
||||
</field>
|
||||
<field id="parent_request_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT UserRequest WHERE id != :this->id AND status NOT IN ('rejected','resolved','closed')]]></filter>
|
||||
<dependencies/>
|
||||
<sql>parent_request_id</sql>
|
||||
<target_class>UserRequest</target_class>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
</field>
|
||||
<field id="parent_request_ref" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>parent_request_id</extkey_attcode>
|
||||
<target_attcode>ref</target_attcode>
|
||||
</field>
|
||||
<field id="parent_problem_id" xsi:type="AttributeExternalKey">
|
||||
<sql>parent_problem_id</sql>
|
||||
<target_class>Problem</target_class>
|
||||
@@ -987,6 +999,9 @@
|
||||
<attribute id="parent_incident_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="parent_request_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="parent_change_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
@@ -1301,90 +1316,20 @@
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildRequestLog()
|
||||
{
|
||||
if (!MetaModel::IsValidClass('UserRequest')) return true; // Do nothing
|
||||
|
||||
$oLog = $this->Get('public_log');
|
||||
$sLogPublic = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPublic != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_incident_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('public_log',$sLogPublic);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
$oLog = $this->Get('private_log');
|
||||
$sLogPrivate = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPrivate != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_incident_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('private_log',$sLogPrivate);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
if (MetaModel::IsValidClass('UserRequest')) {
|
||||
return $this->UpdateChildTicketLog('UserRequest', 'parent_incident_id', ['public_log' => 'public_log', 'private_log' => 'private_log'] );
|
||||
}
|
||||
return true;
|
||||
}]]></code>
|
||||
</method>
|
||||
|
||||
<method id="UpdateChildIncidentLog">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildIncidentLog()
|
||||
{
|
||||
$oLog = $this->Get('public_log');
|
||||
$sLogPublic = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPublic != '')
|
||||
{
|
||||
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";
|
||||
$oChildIncidentSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oIncident = $oChildIncidentSet->Fetch())
|
||||
{
|
||||
$oIncident->set('public_log',$sLogPublic);
|
||||
$oIncident->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
$oLog = $this->Get('private_log');
|
||||
$sLogPrivate = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPrivate != '')
|
||||
{
|
||||
$sOQL = "SELECT Incident WHERE parent_incident_id=:ticket";
|
||||
$oChildIncidentSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oIncident = $oChildIncidentSet->Fetch())
|
||||
{
|
||||
$oIncident->set('private_log',$sLogPrivate);
|
||||
$oIncident->DBUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return $this->UpdateChildTicketLog('Incident', 'parent_incident_id', ['public_log' => 'public_log', 'private_log' => 'private_log']);
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="ComputeImpactedItems">
|
||||
@@ -1558,6 +1503,9 @@
|
||||
<item id="parent_incident_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="parent_request_id">
|
||||
<rank>15</rank>
|
||||
</item>
|
||||
<item id="parent_problem_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
|
||||
@@ -44,6 +44,8 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Open incidents by status',
|
||||
'UI-IncidentManagementOverview-OpenIncidentByAgent' => 'Open incidents by agent',
|
||||
'UI-IncidentManagementOverview-OpenIncidentByCustomer' => 'Open incidents by customer',
|
||||
'Class:Incident/Method:UpdateChildTicketWith:public_log' => '<i><u>Public log entry from parent Incident %2$s:</u></i><br><br>',
|
||||
'Class:Incident/Method:UpdateChildTicketWith:private_log' => '<i>Private log entry from parent Incident [[Incident:%1$s]]:</i><br><br>',
|
||||
]);
|
||||
|
||||
// Dictionnay conventions
|
||||
@@ -193,6 +195,10 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:Incident/Attribute:parent_incident_id+' => '',
|
||||
'Class:Incident/Attribute:parent_incident_ref' => 'Parent incident ref',
|
||||
'Class:Incident/Attribute:parent_incident_ref+' => '',
|
||||
'Class:Incident/Attribute:parent_request_id' => 'Parent request',
|
||||
'Class:Incident/Attribute:parent_request_id+' => '',
|
||||
'Class:Incident/Attribute:parent_request_ref' => 'Parent request ref',
|
||||
'Class:Incident/Attribute:parent_request_ref+' => '',
|
||||
'Class:Incident/Attribute:parent_change_id' => 'Parent change',
|
||||
'Class:Incident/Attribute:parent_change_id+' => '',
|
||||
'Class:Incident/Attribute:parent_change_ref' => 'Parent change ref',
|
||||
|
||||
@@ -179,15 +179,19 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:Incident/Attribute:pending_reason+' => '',
|
||||
'Class:Incident/Attribute:parent_incident_id' => 'Incident parent',
|
||||
'Class:Incident/Attribute:parent_incident_id+' => '',
|
||||
'Class:Incident/Attribute:parent_incident_ref' => 'Référence incident parent',
|
||||
'Class:Incident/Attribute:parent_incident_ref' => 'Réf. incident parent',
|
||||
'Class:Incident/Attribute:parent_incident_ref+' => '',
|
||||
'Class:Incident/Attribute:parent_request_id' => 'Demande parente',
|
||||
'Class:Incident/Attribute:parent_request_id+' => '',
|
||||
'Class:Incident/Attribute:parent_request_ref' => 'Réf. demande parente',
|
||||
'Class:Incident/Attribute:parent_request_ref+' => '',
|
||||
'Class:Incident/Attribute:parent_change_id' => 'Changement parent',
|
||||
'Class:Incident/Attribute:parent_change_id+' => '',
|
||||
'Class:Incident/Attribute:parent_change_ref' => 'Ref Changement parent',
|
||||
'Class:Incident/Attribute:parent_change_ref' => 'Réf. changement parent',
|
||||
'Class:Incident/Attribute:parent_change_ref+' => '',
|
||||
'Class:Incident/Attribute:parent_problem_id' => 'Problème lié',
|
||||
'Class:Incident/Attribute:parent_problem_id+' => '',
|
||||
'Class:Incident/Attribute:parent_problem_ref' => 'Référence problème lié',
|
||||
'Class:Incident/Attribute:parent_problem_ref' => 'Réf. problème lié',
|
||||
'Class:Incident/Attribute:parent_problem_ref+' => '',
|
||||
'Class:Incident/Attribute:related_request_list' => 'Requêtes filles',
|
||||
'Class:Incident/Attribute:related_request_list+' => '',
|
||||
|
||||
@@ -1451,44 +1451,17 @@
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildRequestLog()
|
||||
{
|
||||
return $this->UpdateChildTicketLog('UserRequest', 'parent_request_id', ['public_log' => 'public_log', 'private_log' => 'private_log' ]);
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="UpdateChildIncidentLog">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildIncidentLog()
|
||||
{
|
||||
$oLog = $this->Get('public_log');
|
||||
$sLogPublic = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPublic != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('public_log',$sLogPublic);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
$oLog = $this->Get('private_log');
|
||||
$sLogPrivate = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPrivate != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('private_log',$sLogPrivate);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return $this->UpdateChildTicketLog('Incident', 'parent_request_id', ['public_log' => 'public_log', 'private_log' => 'private_log']);
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="ComputeImpactedItems">
|
||||
@@ -1526,6 +1499,7 @@
|
||||
parent::OnUpdate();
|
||||
$this->Set('last_update', time());
|
||||
$this->UpdateChildRequestLog();
|
||||
$this->UpdateChildIncidentLog();
|
||||
}]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
|
||||
@@ -37,6 +37,8 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'UI-RequestManagementOverview-OpenRequestByCustomer' => 'Open requests by customer',
|
||||
'Class:UserRequest:KnownErrorList' => 'Known Errors',
|
||||
'Class:UserRequest:KnownErrorList+' => 'Known Errors related to Functional CI linked to the current ticket',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:public_log' => '<i><u>Public log automatic copy from parent User Request %2$s:</u></i><br><br>',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:private_log' => '<i>Private log automatic copy from parent User Request [[UserRequest:%1$s]]:</i><br><br>',
|
||||
]);
|
||||
|
||||
// Dictionnay conventions
|
||||
|
||||
@@ -42,6 +42,8 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI-RequestManagementOverview-OpenRequestByCustomer' => 'Requêtes ouvertes par client',
|
||||
'Class:UserRequest:KnownErrorList' => 'Erreurs connues',
|
||||
'Class:UserRequest:KnownErrorList+' => 'Erreurs connues liées à des éléments de configuration impactés par ce ticket',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:public_log' => '<i><u>Copie automatique du log public de la demande parente %2$s:</u></i><br><br>',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:private_log' => '<i>Copie automatique du log privé de la demande parente [[UserRequest:%1$s]]:</i><br><br>',
|
||||
]);
|
||||
|
||||
// Dictionnay conventions
|
||||
|
||||
@@ -1486,44 +1486,8 @@
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildRequestLog()
|
||||
{
|
||||
$oLog = $this->Get('public_log');
|
||||
$sLogPublic = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPublic != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('public_log',$sLogPublic);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
$oLog = $this->Get('private_log');
|
||||
$sLogPrivate = $oLog->GetModifiedEntry('html');
|
||||
if ($sLogPrivate != '')
|
||||
{
|
||||
$sOQL = "SELECT UserRequest WHERE parent_request_id=:ticket";
|
||||
$oChildRequestSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL),
|
||||
array(),
|
||||
array(
|
||||
'ticket' => $this->GetKey(),
|
||||
)
|
||||
);
|
||||
while($oRequest = $oChildRequestSet->Fetch())
|
||||
{
|
||||
$oRequest->set('private_log',$sLogPrivate);
|
||||
$oRequest->DBUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
{
|
||||
return $this->UpdateChildTicketLog('UserRequest', 'parent_request_id', ['public_log' => 'public_log', 'private_log' => 'private_log'] );
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="ComputeImpactedItems">
|
||||
|
||||
@@ -41,6 +41,8 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Menu:UserRequest:MyWorkOrders+' => 'All work orders assigned to me',
|
||||
'Class:Problem:KnownProblemList' => 'Known problems',
|
||||
'Tickets:Related:OpenIncidents' => 'Open incidents',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:public_log' => '<i><u>Public log automatic copy from parent User Request %2$s:</u></i><br><br>',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:private_log' => '<i>Private log automatic copy from parent User Request [[UserRequest:%1$s]]:</i><br><br>',
|
||||
]);
|
||||
|
||||
// Dictionnay conventions
|
||||
|
||||
@@ -42,6 +42,8 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI-RequestManagementOverview-OpenRequestByCustomer' => 'Requêtes ouvertes par organisation',
|
||||
'Class:UserRequest:KnownErrorList' => 'Erreurs connues',
|
||||
'Class:UserRequest:KnownErrorList+' => 'Erreurs connues liées à des éléments de configuration impactés par ce ticket',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:public_log' => '<i><u>Copie automatique du log public de la demande parente %2$s:</u></i><br><br>',
|
||||
'Class:UserRequest/Method:UpdateChildTicketWith:private_log' => '<i>Copie automatique du log privé de la demande parente [[UserRequest:%1$s]]:</i><br><br>',
|
||||
'Menu:UserRequest:MyWorkOrders' => 'Tâches qui me sont assignées',
|
||||
'Menu:UserRequest:MyWorkOrders+' => '',
|
||||
'Class:Problem:KnownProblemList' => 'Problèmes connus',
|
||||
|
||||
@@ -351,6 +351,63 @@
|
||||
}]]></code>
|
||||
<arguments/>
|
||||
</method>
|
||||
<method id="UpdateChildTicketLog">
|
||||
<comment><![CDATA[/**
|
||||
*
|
||||
* Remove the current user associated Person from the contacts_list of this Ticket
|
||||
* No error if there is no associated Person or if the Person is not in the list
|
||||
* @return bool Return true
|
||||
* @param string $sChildClass The class name of the child ticket (e.g. 'Incident', 'UserRequest', etc.)
|
||||
* @param string $sChildParentAttCode The external key in the child class pointing to the parent ticket (e.g. 'parent_request_id')
|
||||
* @param array $aLogAttCodes An array of parent caselog attribute codes and for each the corresponding child log attribute code to update (e.g. ['public_log' => 'private_log'])
|
||||
* So in the example parent.public_log will be copied into each child.private_log
|
||||
* with a prefix using a dictionary entry like 'Class:<parent_ticket_class>/Method:UpdateChildTicketWith:<caselog_attcode>' with one placeholder %1$s for the parent ticket ref
|
||||
* resulting in an entry like "Copy of public log entry from parent Incident I-000123: <log entry from parent.public_log>" in the child private_log
|
||||
*
|
||||
*/]]>
|
||||
</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function UpdateChildTicketLog($sChildClass, $sChildParentAttCode, $aLogAttCodes)
|
||||
{
|
||||
if (!MetaModel::IsValidClass($sChildClass) || (!MetaModel::IsValidAttCode($sChildClass, $sChildParentAttCode))) {
|
||||
ErrorLog::Debug("Invalid class ($sChildClass) or attribute code ($sChildParentAttCode) provided to UpdateChildTicketLog","DataModel");
|
||||
return true; // Do nothing
|
||||
}
|
||||
$oAttDef = MetaModel::GetAttributeDef($sChildClass, $sChildParentAttCode);
|
||||
if (!$oAttDef instanceof AttributeExternalKey || ($oAttDef->GetTargetClass() !== get_class($this))) {
|
||||
ErrorLog::Debug("Attribute $sChildParentAttCode should be an external key of class $sChildClass, pointing to class ".get_class($this),"DataModel");
|
||||
return true; // Do nothing
|
||||
}
|
||||
|
||||
$sParentClass = get_class($this);
|
||||
$aChildEntries = [];
|
||||
foreach ($aLogAttCodes as $sParentAttCode => $sChildAttCode) {
|
||||
if (MetaModel::IsValidAttCode($sParentClass, $sParentAttCode) && MetaModel::GetAttributeDef($sParentClass, $sParentAttCode) instanceof AttributeCaseLog
|
||||
&& MetaModel::IsValidAttCode($sChildClass, $sChildAttCode) && MetaModel::GetAttributeDef($sChildClass, $sChildAttCode) instanceof AttributeCaseLog
|
||||
&& (!utils::IsNullOrEmptyString($this->Get($sParentAttCode)->GetModifiedEntry('html')))) {
|
||||
$aChildEntries[$sChildAttCode] = Dict::Format('Class:'.$sParentClass.'/Method:UpdateChildTicketWith:'.$sParentAttCode, $this->GetKey(), $this->Get('ref')).$this->Get($sParentAttCode)->GetModifiedEntry('html');
|
||||
}
|
||||
}
|
||||
if ($aChildEntries == []) {
|
||||
return true; // nothing to update
|
||||
}
|
||||
|
||||
$sOQL = "SELECT $sChildClass WHERE $sChildParentAttCode = :ticket_id";
|
||||
$oChildSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData($sOQL), [], ['ticket_id' => $this->GetKey()]);
|
||||
while ($oChild = $oChildSet->Fetch()) {
|
||||
if (is_object($oChild)) { // Seems that empty set, maybe in case of OQL syntax error, can return a single empty object instead of no object at all
|
||||
foreach ($aChildEntries as $sAttCode => $sEntry) {
|
||||
$oChild->Set($sAttCode, $sEntry);
|
||||
}
|
||||
$oChild->DBUpdate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
<presentation>
|
||||
<details>
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
// Copyright (c) 2010-2024 Combodo SAS
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Module\iTopTickets;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ormCaseLog;
|
||||
use MetaModel;
|
||||
|
||||
class UpdateChildTicketLogTest extends ItopDataTestCase
|
||||
{
|
||||
public function testUpdateChildTicketLog_PublicLogOnTwoChild(): void
|
||||
{
|
||||
//Given a parent ticket with two child ticket
|
||||
list($iParentTicket, $aChildrenTree) = $this->GivenUserRequests(2);
|
||||
$this->assertCount(2, $aChildrenTree[$iParentTicket], 'The test setup should create exactly two child tickets.');
|
||||
$sParentPublicLogEntry = 'This is a public log entry for the parent ticket.';
|
||||
$oParentTicket = MetaModel::GetObject('UserRequest', $iParentTicket);
|
||||
|
||||
// When I enter a public_log entry for the parent ticket
|
||||
$oParentTicket->Set('public_log', $sParentPublicLogEntry);
|
||||
$oParentTicket->DBUpdate();
|
||||
|
||||
// Then the log should be copied to all descendants and contain parent references recursively
|
||||
$this->AssertLogContainsParentsRefOrKeyRecursively($iParentTicket, $aChildrenTree[$iParentTicket], 'public_log', $sParentPublicLogEntry);
|
||||
}
|
||||
|
||||
public function testUpdateChildTicketLog_PrivateAndPublicLog(): void
|
||||
{
|
||||
//Given a parent ticket with two child ticket
|
||||
list($iParentTicket, $aChildrenTree) = $this->GivenUserRequests(3);
|
||||
$sParentPublicLogEntry = 'This is a public log entry for the parent ticket.';
|
||||
$sParentPrivateLogEntry = 'This is a private log entry for the parent ticket.';
|
||||
|
||||
// When I enter both a public_log and a private_log entry for the parent ticket
|
||||
$oParentTicket = MetaModel::GetObject('UserRequest', $iParentTicket);
|
||||
$oParentTicket->Set('public_log', $sParentPublicLogEntry);
|
||||
$oParentTicket->Set('private_log', $sParentPrivateLogEntry);
|
||||
$oParentTicket->DBUpdate();
|
||||
|
||||
// Then both logs should be copied to all descendants and keep ancestor references recursively
|
||||
$this->AssertLogContainsParentsRefOrKeyRecursively($iParentTicket, $aChildrenTree[$iParentTicket], 'public_log', $sParentPublicLogEntry);
|
||||
$this->AssertLogContainsParentsRefOrKeyRecursively($iParentTicket, $aChildrenTree[$iParentTicket], 'private_log', $sParentPrivateLogEntry);
|
||||
}
|
||||
|
||||
public function testUpdateChildTicketLog_PrivateLogOnMultipleLevels(): void
|
||||
{
|
||||
//Given a parent ticket with two child ticket
|
||||
list($iParentTicket, $aChildrenTree) = $this->GivenUserRequests(1, 4);
|
||||
$sParentPrivateLogEntry = 'This is a private log entry for the parent ticket.';
|
||||
|
||||
// When I enter both a public_log and a private_log entry for the parent ticket
|
||||
$oParentTicket = MetaModel::GetObject('UserRequest', $iParentTicket);
|
||||
$oParentTicket->Set('private_log', $sParentPrivateLogEntry);
|
||||
$oParentTicket->DBUpdate();
|
||||
|
||||
// Then the private log should be copied on each level with parent + grand-parent +... references
|
||||
$this->AssertLogContainsParentsRefOrKeyRecursively($iParentTicket, $aChildrenTree[$iParentTicket], 'private_log', $sParentPrivateLogEntry);
|
||||
}
|
||||
|
||||
private function AssertLogContainsParentsRefOrKeyRecursively(int $iParentTicket, array $aChildrenTree, string $sLogAttCode, string $sExpectedEntry, array $aAncestors = []): void
|
||||
{
|
||||
$oParentTicket = MetaModel::GetObject('UserRequest', $iParentTicket);
|
||||
$aAncestorsToFind = array_merge($aAncestors, [[
|
||||
'id' => (string) $iParentTicket,
|
||||
'ref' => (string) $oParentTicket->Get('ref'),
|
||||
]]);
|
||||
|
||||
foreach ($aChildrenTree as $iChildOrIndex => $aChildNodeOrId) {
|
||||
if (is_array($aChildNodeOrId)) {
|
||||
$iChildTicket = (int) $iChildOrIndex;
|
||||
$aGrandChildrenTree = $aChildNodeOrId;
|
||||
} else {
|
||||
$iChildTicket = (int) $aChildNodeOrId;
|
||||
$aGrandChildrenTree = [];
|
||||
}
|
||||
|
||||
$oChildTicket = MetaModel::GetObject('UserRequest', $iChildTicket);
|
||||
$sLastLogEntry = $oChildTicket->Get($sLogAttCode)->GetLatestEntry();
|
||||
$this->assertNotEmpty($sLastLogEntry, "The $sLogAttCode entry was not copied to child ticket #$iChildTicket.");
|
||||
$this->assertStringContainsString($sExpectedEntry, $sLastLogEntry, "The $sLogAttCode entry on child ticket #$iChildTicket does not contain the original parent entry.");
|
||||
foreach ($aAncestorsToFind as $aAncestor) {
|
||||
$bContainsAncestorRef = strpos($sLastLogEntry, $aAncestor['ref']) !== false;
|
||||
$bContainsAncestorId = strpos($sLastLogEntry, $aAncestor['id']) !== false;
|
||||
$this->assertTrue(
|
||||
$bContainsAncestorRef || $bContainsAncestorId,
|
||||
"The $sLogAttCode entry on child ticket #$iChildTicket does not contain ancestor ref '{$aAncestor['ref']}' nor ancestor id '{$aAncestor['id']}'."
|
||||
);
|
||||
}
|
||||
|
||||
if ($aGrandChildrenTree !== []) {
|
||||
$this->AssertLogContainsParentsRefOrKeyRecursively($iChildTicket, $aGrandChildrenTree, $sLogAttCode, $sExpectedEntry, $aAncestorsToFind);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function GivenUserRequests(int $iCount, int $iLevel = 2): array
|
||||
{
|
||||
$iOrg = $this->GivenObjectInDB('Organization', [
|
||||
'name' => 'Test Organization for Log Update',
|
||||
]);
|
||||
// Given a parent ticket
|
||||
$iParentTicket = $this->GivenObjectInDB('UserRequest', [
|
||||
'title' => 'Parent Ticket for Log Update Test',
|
||||
'description' => 'This is the parent ticket for testing log updates.',
|
||||
'org_id' => $iOrg,
|
||||
'ref' => 'R-00001',
|
||||
]);
|
||||
|
||||
$iRemainingLevels = max(0, $iLevel - 1);
|
||||
$iRefCounter = 1;
|
||||
$aChildrenTree = [
|
||||
$iParentTicket => $this->GivenChildTicketsRecursive($iParentTicket, $iCount, $iRemainingLevels, $iOrg, $iRefCounter),
|
||||
];
|
||||
|
||||
return [$iParentTicket, $aChildrenTree];
|
||||
}
|
||||
|
||||
private function GivenChildTicketsRecursive(int $iParentTicket, int $iCount, int $iRemainingLevels, int $iOrg, int &$iRefCounter): array
|
||||
{
|
||||
if ($iRemainingLevels <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$aChildren = [];
|
||||
for ($i = 1; $i <= $iCount; $i++) {
|
||||
$iRefCounter++;
|
||||
$sRef = sprintf('R-%05d', $iRefCounter);
|
||||
$iChildTicket = $this->GivenObjectInDB('UserRequest', [
|
||||
'title' => "Child Ticket $sRef for Log Update Test",
|
||||
'description' => "This is child ticket $sRef for testing log updates.",
|
||||
'org_id' => $iOrg,
|
||||
'parent_request_id' => $iParentTicket,
|
||||
'ref' => $sRef,
|
||||
]);
|
||||
|
||||
if ($iRemainingLevels > 1) {
|
||||
$aChildren[$iChildTicket] = $this->GivenChildTicketsRecursive($iChildTicket, $iCount, $iRemainingLevels - 1, $iOrg, $iRefCounter);
|
||||
} else {
|
||||
$aChildren[] = $iChildTicket;
|
||||
}
|
||||
}
|
||||
|
||||
return $aChildren;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user