Flag Tickets waiting for a 3rd party
Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.
- learning:
- Add a state to a lifecycle and count time spent in it
- level:
- Advanced
- domains:
- XML, Stopwatch, Automation, Lifecycle
- min version:
- 2.3.0
In this tutorial, we want to identify Tickets for which the support team is waiting for a 3rd party provider information/action, and cannot work on the ticket without it. In order to achieve this goal, we will:
-
Add a new state to the UserRequest, indicating that we are waiting for the 3rd party provider
-
Add a new stimulus, to move a User Request in that new state
-
Add two transitions, to allow the UserRequest to be moved to and out of this new state
In a second step we want to track how much time was spent waiting for the provider on each ticket. This requires to:
-
Add a stopwatch attribute on UserRequest class, to count when the ticket is in “pending_provider” state.
-
Add a sub-item field to display the time spent while waiting for provider.
-
Display the total time spent waiting for the 3rd party provider only in some states of the UserRequest
Declare a new state
- itop_design / classes / class@UserRequest / fields
-
<!-- Add a new state value to the existing status --> <field id="status" _delta="must_exist"> <values> <value id="pending_provider" _delta=define">pending_provider</value> </values> </field>
- itop_design / dictionaries / dictionary@EN US
-
<!-- Give a label to the new state --> <entry id="Class:UserRequest/Attribute:status/Value:pending_provider" _delta="define"> <![CDATA[Pending provider]]> </entry>
-
Note the dictionary code logic for an enum value: Class:<class_name>/Attribute:<attribute_code>/Value:<value_code>
Add a stimulus
The stimulus correspond to the button and “Other actions” menu which will be proposed on the details of the UserRequest, when this action will be possible.
- itop_design / classes / class@UserRequest / lifecycle
-
<stimuli> <!-- Add a new stimulus to switch to pending_provider state --> <stimulus id="ev_pending_provider" xsi:type="StimulusUserAction" _delta="define"/> </stimuli>
- itop_design / dictionaries / dictionary@EN US / entries
-
<entry id="Class:UserRequest/Stimulus:ev_pending_provider" _delta="define"> <![CDATA[Wait for Provider]]> </entry>
-
Note the dictionary code logic for a stimulus: Class:UserRequest/Stimulus:stimulus_id
-
The label of a stimulus is applied on all transitions using this stimulus.
-
In general a given stimulus always end-up on the same state.
-
The stimulus declaration does not specify how it will be used, it can be used for any transition between any states.
Add state and transitions
A transition is defined by:
-
a starting state,
-
a stimulus, which triggers the transition and is proposed as a possible action on the starting state
-
an ending state, which is the resulting state in which the object will be after the transition
Here we want to propose two possible transitions:
-
One transition from the “assigned” to “pending_provider” state using the newly created stimulus “ev_pending_provider”. It will be used when the support team is waiting for the 3rd party provider to act and respond.
-
One transition to go back from “pending_provider” to “assigned” using the classic “ev_assign” stimulus. It will be used when provider has replied/act and that support team can go on with the Ticket resolution.
- itop_design / classes / class@UserRequest / lifecycle
-
<states> <!-- This level define the state we are in --> <state id="assigned" _delta="must_exist"> <transitions> <!-- this define an available transition from the above state --> <transition id="ev_pending_provider" _delta="define"> <!-- This define the stimulus which trigger the transition --> <!-- on a given state there can only be one transition triggered by a given stimulus --> <stimulus>ev_pending_provider</stimulus> <!-- This define on which state the UserRequest will end-up --> <target>pending_provider</target> <actions/> </transition> </transitions> </state> <!-- From the new state --> <state id="pending_provider" _delta="define"> <flags /> <!-- it's a mandatory tag, even if empty --> <transitions> <!-- we want to assign the ticket back to the support team --> <transition id="ev_assign"> <stimulus>ev_assign</stimulus> <target>assigned</target> <actions/> </transition> </transitions> <!-- The fields are the same as in "assigned" state --> <inherit_flags_from>assigned</inherit_flags_from> </state> </states>
Counting time waiting for 3rd party
In this complementary usecase, we want to track how much time was spent waiting for the provider on each ticket. For this we will
-
Add a stopwatch attribute on UserRequest class, to count when the ticket is in “pending_provider” state.
-
Add a sub-item field to display the time spent while waiting for provider.
-
Display the total time spent waiting for the 3rd party provider only in some states of the UserRequest
Add a stopwatch
- itop_design / classes / class@UserRequest / fields
-
<!-- Add a stopwatch to count the timespent in this state --> <field id="providerstopwatch" xsi:type="AttributeStopWatch" _delta="define"> <states> <!-- here are the states during which the stopwatch is counting time --> <state id="pending_provider">pending_provider</state> </states> <working_time/> <thresholds/> <always_load_in_tables>true</always_load_in_tables> </field>
- itop_design / dictionaries / dictionary@EN US / entries
-
<entry id="Class:UserRequest/Attribute:providerstopwatch" _delta="define"> <![CDATA[Provider stopwatch]]> </entry>
-
This is the simplest use you can make of a stopwatch, just counting time spent in particular states
Track time spent
This step is mandatory to be able to display this information in a form and query it by OQL.
- itop_design / classes / class@UserRequest / fields
-
<!-- Declaring this stopwatch sub-item is required to display or query it --> <field id="pending_provider_delay" xsi:type="AttributeSubItem" _delta="define"> <target_attcode>providerstopwatch</target_attcode> <!-- Possible item_code: timespent, started, laststart, stopped --> <item_code>timespent</item_code> </field> </fields>
-
You can also declare other sub-items.
- itop_design / dictionaries / dictionary@EN US / entries
-
<entry id="Class:UserRequest/Attribute:pending_provider_delay" _delta="define"> <![CDATA[Provider time spent]]> </entry>
Display Stopwatch
In this example, we will display the stopwatch it-self. This field is rather special as it is a composite one, it contains sub-information, which are all displayed. We have decided to display the stopwatch all the time, regardless if it is running or not. You will see that the displayed data will not be available in some state.
Sub-items can also be displayed independently, assuming you have
declared them, as we just did for the sub-item
timespent
. So we will also display the time spent.
- itop_design / classes / class@UserRequest
-
<!-- Display the 2 new fields in the details of the UserRequest --> <presentation> <details _delta="must_exist"> <items> <!-- First column of the UserRequest display --> <item id="col:col1"> <items> <item id="fieldset:Ticket:moreinfo"> <items> <!-- Add the provider timespent delay --> <item id="pending_provider_delay" _delta="define"> <rank>80</rank> </item> <!-- This displays a stopwatch (including some sub-items) --> <!-- This will help you to understand how a stopwatch behave --> <item id="providerstopwatch" _delta="define"> <rank>90</rank> </item> </items> <rank>20</rank> </item> </items> </item> </items> </details> </presentation>
Display time spent
Because the time spent is only calculated when the stopwatch is stopping - so here when the UserRequest exits the “pending_provider” state -
-
it should not be displayed in state “pending_provider”, as it does not provide an accurate information
-
we decided not to display it in state “new”, as it's useless and empty
-
we decided to display it when the ticket is resolved or closed, in read only as it should not be modified by the user.
We have defined in the presentation, where that
field need to be displayed, now we can modulate
when it should be available, by defining for each
state, if this field should be hidden
or read
only
.
-
When we define a field to be
hidden
in statenew
, as states are chained in standard datamodel, this propagates to all following states. -
When we define it to be read only in state
resolved
, it overwrites thehidden
flag -
As
closed
is changed toresolved
state, it is still visible
- itop_design / classes / class@UserRequest
-
<lifecycle> <states> <state id="new" _delta="must_exist"> <flags> <!-- Hide the pending provider_delay, it will propagate to all chained states --> <attribute id="pending_provider_delay" _delta="define"> <hidden/> </attribute> </flags> </state> <state id="resolved" _delta="must_exist"> <flags> <attribute id="pending_provider_delay" _delta="define"> <!-- Read_only takes precedence on hidden ??? --> <read_only/> </attribute> </flags> </state> </states> </lifecycle>
Here is the result on a User Request for which was moved three
time back and force between “Assigned” and “Pending provider”, as a
result, “Elapsed” does not correspond to the difference between
“Started” and “Stopped”. But you can see that 7*60s + 49s = 469s,
as “Provider time spent” is just a nice display of the “Elapsed”
sub-item (=timespent
)
Behavior of the Stopwatch
In this part, we will show what the stopwatch contains along the User Request life
1. Stopwatch never started:
2. User Request is moved from “Assigned” to Pending provider for the first time:
-
stopwatch is running, so “Elapsed” (= timespent) is not available
-
“Started” and “LastStart” are equal
3. User Request is moved back from “Pending Provider” to Assigned for the first time:
-
stopwatch is stopped, so “Elapsed” (= timespent) is available
-
“LastStart” is empty when not running
-
“Stopped” is documented
4. User Request is moved again from “Assigned” to Pending provider:
-
stopwatch is running, so “Elapsed” (= timespent) is not available
-
“Started” is unchanged
-
“LastStart” correspond to the last time the stopwatch has started
-
“Stopped” is empty when running
5. User Request is moved back again from “Pending Provider” to Assigned:
-
stopwatch is stopped, so “Elapsed” (= timespent) is available
-
“Started” is unchanged
-
“LastStart” is empty again, as the stopwatch is stopped
-
“Stopped” is documented again and correspond to the last stop
-
Note that “Elapsed” is not equal to the difference between “Started” and “Stopped”
A stopwatch is automatically computed and cannot be edited by a user:
Full XML
Here is the consolidated XML for this tutorial
- itop_design
-
<classes> <class id="UserRequest"> <fields> <!-- Add a new state value to the existing status --> <field id="status" _delta="must_exist"> <values> <value id="pending_provider" _delta="define">pending_provider</value> </values> </field> <!-- Add a stopwatch to count the timespent in this state --> <field id="providerstopwatch" xsi:type="AttributeStopWatch" _delta="define"> <states> <!-- this are the states, during which the stopwatch is counting time --> <state id="pending_provider">pending_provider</state> </states> <working_time/> <thresholds/> <always_load_in_tables>true</always_load_in_tables> </field> <!-- Declaring this stopwatch sub-item is required to display or query it --> <field id="pending_provider_delay" xsi:type="AttributeSubItem" _delta="define"> <target_attcode>providerstopwatch</target_attcode> <!-- Possible item_code: timespent, started, laststart, stopped --> <item_code>timespent</item_code> </field> </fields> <lifecycle> <stimuli> <!-- Add a new stimulus to switch to pending_provider state --> <stimulus _delta="define" id="ev_pending_provider" xsi:type="StimulusUserAction"/> </stimuli> <states> <!-- This level define the state we are in --> <state id="assigned" _delta="must_exist"> <transitions> <!-- this define an available transition from the above state --> <transition id="ev_pending_provider" _delta="define"> <!-- This define the stimulus which trigger the transition --> <!-- on a given state there can only be one transition triggered by a given stimulus --> <stimulus>ev_pending_provider</stimulus> <!-- This define on which state the UserRequest will end-up --> <target>pending_provider</target> <actions/> </transition> </transitions> </state> <!-- From the new state --> <state id="pending_provider" _delta="define"> <flags /> <!-- Also empty it's a mandatory tag --> <transitions> <!-- we want to assign the ticket back to the support team --> <transition id="ev_assign"> <stimulus>ev_assign</stimulus> <target>assigned</target> <actions/> </transition> </transitions> <!-- The fields are the same as in "assigned" state --> <inherit_flags_from>assigned</inherit_flags_from> </state> <state _delta="must_exist" id="new"> <flags> <!-- Hide the pending provider_delay, it will propagate to all chained states --> <attribute id="pending_provider_delay" _delta="define"> <hidden/> </attribute> </flags> </state> <state id="resolved" _delta="must_exist"> <flags> <attribute id="pending_provider_delay" _delta="define"> <!-- Read_only takes precedence on hidden ??? --> <read_only/> </attribute> </flags> </state> </states> </lifecycle> <!-- Display the 2 new fields in the details of the UserRequest --> <presentation> <details _delta="must_exist"> <items> <!-- First column of the UserRequest display --> <item id="col:col0"> <items> <item id="fieldset:Ticket:moreinfo"> <items> <!-- Add the provider timespent delay --> <item id="pending_provider_delay" _delta="define"> <rank>80</rank> </item> <!-- This displays a stopwatch (including some sub-items) --> <!-- This will help you to understand how a stopwatch behave --> <item id="providerstopwatch" _delta="define"> <rank>90</rank> </item> </items> <rank>20</rank> </item> </items> </item> </items> </details> </presentation> </class> </classes> <dictionaries> <dictionary id="EN US"> <entries> <!-- Give a label to the new state --> <entry id="Class:UserRequest/Attribute:status/Value:pending_provider" _delta="define"> <![CDATA[Pending provider]]> </entry> <entry id="Class:UserRequest/Attribute:pending_provider_delay" _delta="define"> <![CDATA[Provider time spent]]> </entry> <entry id="Class:UserRequest/Stimulus:ev_pending_provider" _delta="define"> <![CDATA[Wait for Provider]]> </entry> <entry id="Class:UserRequest/Attribute:providerstopwatch" _delta="define"> <![CDATA[Provider stopwatch]]> </entry> </entries> </dictionary> </dictionaries>