Planned User Request (advanced)
Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.
- learning:
- Add a state and count time spent in it
- level:
- Advanced
- domains:
- XML, Stopwatch, Automation, Lifecycle
- min version:
- 2.3.0
In this tutorial, we will explore further User Request where TTO start on a planned date tutorial, proposing solutions for the identified limitations:
-
Why using AfterInsert and not iApplicationExtension
-
How to take into account a modification of the “planned date”, after the creation, during
new
orscheduled
state? -
How to prevent the other transitions to be proposed?
🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧
Work in progress…
Question & Answers
Question: Why automatically switch to a state
“scheduled” when a planned_date is proposed?
Answer: This mechanism is the one used by Auto dispatch
ticket to a team and Approval process automation
But you could decide to propose this transition as a user choice
and on that transition, make the planned_date
field
mandatory, but in that case, if combined with Approval process automation,
user won't be able to schedule a UserRequest which is under
approval, unless you schedule after approval. There is an
imcompatibility if you use Auto dispatch
ticket to a team as the Request might be auto-dispaltched
before you schedule it. Then add also an ev_schedule
transition from dispatched
to scheduled
,
so that the user can still scheduled a dispatched Ticket. Hopefully
when pushed back to new
after the delay, it will be
dispatched again.
iApplicationObjectExtension
it's officially not
possible to define the order in which classes implementing this
interface will be called, but for the case of Approval extented
which we wanted to execute before AutoDispatch, we have done it by
a optional module dependency, which implies a module load ordering,
which until now is the same as the calling ordering. 🚧 Nous ne
voulons pas en faire la publicité, car ça pourrait bien changer
!!!!Question: When you create a UserRequest with a date and
we do Assign, it crashs with Fatal Error, how to avoid
it?
Answer: Extensions Auto dispatch
ticket to a team and Approval process automation hide
in the console (🚧 and in portal?), all other actions which could be
failing such as “Assign”, “Dispatch”, “Wait for approval”,…
You can avoid this by overloading
DisplayBareProperties()
- class:UserRequest
-
function DisplayBareProperties(WebPage $oPage, $bEditMode=false, $sPrefix='', $aExtraParams=array()) { $aFieldsMap = parent::DisplayBareProperties($oPage, $bEditMode, $sPrefix, $aExtraParams); if ($bEditMode && $oObject->GetState()='new') { $oPage->add_ready_script( <<<EOF $('button.action[name="next_action"]').hide(); EOF ); } return $aFieldsMap; }
or by implementing iApplicationUIExtension
(OnDisplayProperties()) as the listed extensions are
doing.
- main.my-extension.php
-
public function OnDisplayProperties($oObject, WebPage $oPage, $bEditMode = false) { // Hiding transition buttons if ($bEditMode && $oObject instance of UserRequest && $oObject->GetState()='new') { $oPage->add_ready_script( <<<EOF $('button.action[name="next_action"]').hide(); EOF ); } }
Risk of overwriting
When you define one of the DBObject overwritable methods, be aware that it may have been done already within the standard iTop datamodel. If it is the case, at setup/toolkit compilation, as you add the method with a _delta=“define” it will fails if it exists already. In that case, you can do a “redefine”, but then mirror the existing code or you will break the current behavior of iTop.
For example in the Standard Datamodel, the class UserRequest defines already those methods
- class:UserRequest
-
public function ComputeValues() { $this->Set('priority', $this->ComputePriority()); return parent::ComputeValues(); } public function DoCheckToWrite() { parent::DoCheckToWrite(); if (!$this->IsNew() && ($this->Get('parent_request_id') == $this->GetKey())) { $this->m_aCheckIssues[] = Dict::Format('Class:UserRequest/Error:CannotAssignParentRequestIdToSelf'); } } protected function OnInsert() { $this->ComputeImpactedItems(); $this->SetIfNull('last_update', time()); $this->SetIfNull('start_date', time()); } protected function OnUpdate() { parent::OnUpdate(); $aChanges = $this->ListChanges(); if (array_key_exists('functionalcis_list', $aChanges)) { $this->UpdateImpactedItems(); } $this->Set('last_update', time()); $this->UpdateChildRequestLog(); }