Sidebar

Combodo

iTop Extensions

Customized request forms

name:
Customized request forms
description:
Define personalized request forms based on the service catalog. Add extra fields for a given type of request.
version:
2.4.3
release:
2024-08-01
itop-version-min:
2.7.0
code:
combodo-customized-request-forms
state:
stable
alternate-name:
Request Templates
diffusion:
iTop Hub
php-version-max:
PHP 8.3
Check the upgrade process, if you upgrade from a version before 2.1.0 of this extension.

Features

This module provides the capability to add dynamically additional fields on a User Request in order to better qualify it. The additional fields proposed will be different based on the selected Service / Service Subcategory.

For instance when a user asks for a “new virtual machine”, then we may want him to provide the number of CPUs, the quantity of RAM and the type of OS in structured fields rather than hoping that the user will provide them by himself, in the Description field.

You just have to define your template and then when a user creates a ticket, the additional fields will appear in the ticket edition form, based on the selected service subcategory.

A request template is related to a service subcategory. A request template can add one or multiple additional fields to User Requests. The additional fields can be of the following types:

  • Date and Date Time
  • String (formated with regular expression if needed)
  • Text area
  • CSV list
  • List based on OQL query
  • Duration
  • Readonly/hidden fields

Revision History

Release Date Version Comments
2024-08-01 2.4.3 * N°6353 - Add tooltips on Request Template and Field classes
* N°7599 - Migrate usage of WebPage::add_linked_script()
* N°7443 - url in read-only attribute are displayed different between console and portal
2023-06-28 2.4.2 * N°6725 - Customizing Request Template, generates presentation error messages in Designer during MTP
* N°6532 - Remove unnecessary PHP 7.4 type hint breaking compatibility with iTop 2.7 and iTop 3.0
2023-07-13 2.4.1 * N°6540 - PHP 8.1: Fix deprecated notice for null value passed to strlen() function
2023-06-28 2.4.0 * PHP 7.4 minimum required
* N°6220 - Add PHP 8.2 compatibility
* N°6140 - Add HTML metadata on custom fields to be aligned with regular fields
* N°6236 - Read Request template data though the REST/JSON API (iTop 3.1.0+)
* N°1150 - Write request template data though the REST/JSON API (iTop 3.1.0+)
2022-08-31 2.3.4 * Handle initial values on dependent fields (with iTop 3.0.2+)
* Improve compatibility with other extensions using also templates-base module
* Add PHP 8.1 compatibility
* Internal: Add missing dependancy to template-base module
2022-03-22 2.3.3 * Remove deprecated function SetupPage::log_info
2021-12-21 2.3.2 * Spanish translation
2021-09-01 2.3.1 * Add TemplateField.max_combo_length to specify when to switch to autocomplete
* Add 3.0 compatibility
* Avoid fatal error if another XML customization deletes the ones from this XML file
2021-12-17 2.2.1 * Fix “undefined index: display_condition” notice when displaying UserRequest
* Avoid fatal error if DM customization from the XML file are deleted by another XML delta
2021-04-27 2.2.0 * Add TemplateField.display_condition to display or hide a field depending on another field value
2020-12-02 2.1.5 * Fix wrong module version for template-base and itop-request-template-portal
* Fix incompatibility with Request Template, for iTop with a portal different than the standard portal
* Fix request template indexing CLI (encoding/truncate issue)
2020-07-15 2.1.4 * Fix issue calling TruncateFieldValue in TemplateValue::Set
2020-04-29 2.1.2 Template field generation script now handle correctly deleted request templates
2020-03-26 2.1.1 - Fix regression when submitting with transition form
- Fix remove TemplateFieldValue on object deletion
2019-12-04 2.1.0 - Request template fields are now queryable
- Fix missing menus on request template view
- Update DE translations
2019-01-30 2.0.14 Fix regression introduced in 2.0.10: custom date formats no longer working
2018-12-19 2.0.13 - Fix unnecessary error messages popping on the screen when a DoCheckToWrite fails
- Fix execution notice (check array existence)
- Update spanish translations (thanks to Miguel Turrubiates!)
2018-06-27 2.0.12 Add DE translation
2018-06-26 2.0.11 ES + BR translations, default search attributes
2018-01-26 2.0.10 Ticket fields can now be used in customized forms.
Also fixed 2 bugs for usage in notifications templates ($service_details$) :
- N°1079 When the user leaves it undefined, then this is shown as an error message in the email: “Custom field error: Wrong format: missing template_data” ;
- N°1080 When a field aims at selecting an object, the email body shows the id of the selected object.
2018-01-05 2.0.9 Customized forms are now compatible with Incident
2017-11-13 2.0.8 Service_details is now documented on UserRequest creation before notification
2017-09-08 2.0.7 Request template value not set in notification when creating an object
2017-03-01 2.0.6 Added module setting to reset template fields value when changing to a different template that contains fields with same codes
2016-12-13 2.0.5 Fixed issues when used in cunjunction with the legacy portal. Requires iTop > 2.3.2 for the date/time pickers to work fine
2016-11-29 2.0.4 Implemented placeholders (e.g. $this->html(service_details)$. Requires iTop > 2.3.1 for the placeholders to work fine.
2016-09-08 2.0.3 Added validation pattern to Date and DateTime fields. Fixed a PHP Warning when launching the cron manually.
2016-09-02 2.0.2 Hidden and Read-only fields are now rendered like multiline strings (like a textarea, though it is read-only) - Note that this will work fine in the console with iTop 2.3.0+, but requires iTop > 2.3.1 to take advantage of this enhancement in the enhanced customer portal (no change in the legacy portal!)
2016-08-03 2.0.1 Support of the console and the enhanced customer portal (both require iTop 2.3.0, otherwise the behavior is the same as 1.0.5)
2015-11-26 1.0.5 Fix for crash when submitting a ticket from the portal for a template with an ENUM field containing some special characters.
2015-09-29 1.0.4 Fix for a crash when a “drop-down list” field contains some weird characters (accents, question marks…) at the beginning of the list of values.
2014-12-10 1.0.3 Cosmetics on the module name.
2014-04-03 1.0.2 Minor fix to allow non admin users to import Template fields in CSV.
2014-03-10 1.0.1 Bug fix for template fields with the same name as an attribute of the object.
2014-02-05 1.0.0 First version, never validated.

Limitations

  • This extension is designed for UserRequest and Incident tickets only. See Q&A: on "Change" class for customizing it for another class.

on usage

  • When defining Fields give them different labels or only the first one will be displayed in read mode.
  • Be cautious, when you define possible values in a Request Template Field, with an OQL query, this features has limitations
    • You cannot depend on (in the OQL query) an ExternalField declared on the Ticket (such as team_name), as the proposed values won't be refreshed upon a change of team. Classical external fields you may be tempted to use but should not: caller_name, org_name, agent_name, team_name, service_name, servicesubcategory_name. See Q&A: Values not refreshed for examples and workaround.
    • You cannot use (in the OQL query) a Ticket field which is not displayed to the user on the Portal, as it crashes the Portal.
    • Access restriction: The OQL query will display all objects on the Portal, it ignores user scopes. The only security filtering applied are related to the User Profiles and Allowed Organizations, not the portal Scopes. Include those constraints in the OQL query if this is a requirement for you.
    • You cannot on that OQL query specify any “ignore_silo” constrains.
    • Show obsolete data user preference is not taken into account. If you don't want obsolete objects to be proposed, put it in your query.
      If user preference were taken into account, you would not be able to request through a service the reactivation of an obsolete object, selected in a Request Template field. In such case, some users could not fill the request because they would not see the obsolete objects, painful, no!.
    • Conditional field comes with a limitation, if it is not displayed in the initial form, then its initial value is never displayed. fixed in 2.3.4
  • The type of data which can be displayed and requested within a request Template does not supports all fields,
    • You cannot prompt the user for Image, File, HTML, nor multi-valued fields like TagSet, EnumSet, Caselog,…
    • You cannot provide html information such as clickable URL, image, file,…
  • When creating a UserRequest, there is no way to prefill the fields of the service_details request template, as they are not known by the data model
  • On notification the only supported placeholder is $this->service_details$ which displays the full content of the Request template. It is not possible to only reference a single field of a template.

on import & export

  • Because of its design, some “standard” itop capabilities are not available.
    • You cannot do a CSV export of UserRequest with one column per Request Template Fields. You will have to do it with Excel.
    • You cannot CSV import UserRequest with their filled Template (service_details field)
    • You cannot fill through a REST API call, the template of a UserRequest (service_details field)
    • You cannot in the UI, filter UserRequest based on values they have in the dynamic fields brought by request templates
    • The way to query UserRequest having one value in a particular request template field and another value in another request template field, is rather tricky due to iTop OQL limitation, see Q&A: Reporting for how to do it.

Installation & upgrade

Use the Standard installation process for this extension.

Upgrade: In order to be able to search for old User Requests which do have a particular value set in a request template, the iTop administrator need to run once a special page which explode every (User Request) template data into new tables, so it can be queried with OQL.

php populateTemplateFieldValue.php --append

You can either use “--append” or “--reset”, same results, might differ in execution time.

  • --reset recomputes from scratch
  • --append explode only the template data which have not been exploded yet

Configuration

The following settings can be adjusted in the iTop configuration file, in the section itop-request-template:

Parameter Type Description Default Value
copy_to_log string The attribute into which the template values should be copied. Set to an empty string to disable this behavior. public_log

The following settings can be adjusted in the iTop configuration file, in the section templates-base:

Parameter Type Description Default Value
hidden_fields_profiles string CSV list of profiles. If the user has ANY of the listed profile, she will NOT see the fields of type “hidden”. Portal user
reset_fields_on_template_change boolean If set to “true”, fields value will be reset when changing template, even if some of the fields have the same code. false
view_extra_data string FIXME relations

Usage

Create request template

From the Service Management menu, click on “Request template”:  Customized request forms menu

The pages show a list of already defined request templates. Click on the button “new” to create a new one:

 Customized request forms creation

A request template is identified by its name the related service and service sub category.

The label is used on the portal to select a template if several are defined for a given service sub category.

The tab “Fields” is used to define the fields of the template:

 Customized request forms fields list

Click on “Create a new field” to define a new one:

 Customized request forms field creation

Here is a complete description of the properties:

Property Description Example
Code Unique identifier, that can be used in the queries defined in another field. This value must be made of alphanumeric characters and cannot start with a number model
Order An integer that defines in which order the fields are displayed in the form 3
Label Label seen by the user who is prompted for entering a value. Must be unique within a Template Device Model
Mandatory Wether or not the user must enter/select a value yes
Input type … see a detailed description below List
Values (OQL or CSV) Used for drop-down lists only to define the list of allowed values for this element. This can be either a comma separated list of values (e.g. “high,medium,low”). The OQL can have a parameter in the form :template->code, where code is the code of another field. It can also use placeholder like :current_contact->org_id or :this->org_id which refer to the customer of the Ticket SELECT Model WHERE brand_id = :template->brand
Initial value Used to set an initial value for text or text area fields xyz
Format Allows you to define a regular expression for validating text fields ^[a-zA-Z]$
Condition New in 2.2.0 Condition on another field to display current field :template->fieldcode1!=''
Auto-complete threshold New in 2.3.1 Threshold of possible values above which the input switch to auto-completion. Applicable for List and Drop-down list only if Values is an OQL. Must be an integer. It uses max_combo_length from iTop configuration when left empty 500

The syntax of a condition must be exactly following:

  • :template->
  • a field code (Should be a field of type List or Dropdown with a number of values below max_combo_length - Otherwise set on the Field an Auto-complete threshold above the number of returned values)
  • an operator = or !=
  • a fixed value which can be '' for empty or any text string inside simple quote

No blank or anything like that, except within the quotes of your value. Example: :template->fieldcode2='no way'
You cannot define a condition on 2 values or a condition on multiple fields.

Caution, condition on value is case sensitive and blank sensitive.
  • :template->fieldcode2='no' will not work if possible values for fieldcode2 are yes, no.
  • :template->fieldcode2='No' will not work if possible values for fieldcode2 are yes,no.

Remove value surrounding blank in Values (OQL or CSV), otherwise the real value contains the spaces

When providing “Values” in CSV: write all values in one line, without carriage return
Do not enter space before and after the comma between values.
When providing “Values” in OQL: do not use friendlyname in the OQL query.

Defining a dependent field, on a master field which would be a Text, a Text area, a Date, a Date time or a Dropdown list in autocomplete mode, is not well handled by the UI, it's blinking, user can loose their entry, the behavior isn't user friendly.

To limit to … use this regex within Format
an email [a-zA-Z0-9._&'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,}
a phone number ^\+?[0-9\ ]{8,20}$
a url https?,ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\$_.-]*)?

The input type can have one of the following values:

Input type Description
Date A pure date, entered by the mean of a calendar, or directly typed in
Date and time Date and time, entered by the mean of a calendar, or directly typed in
Drop-down list A list as defined by the property Values
Duration A time lapse
Hidden A value that will not be seen by the end-user (customer portal), but it will be seen by an agent (console) in modification only. The value is set by the mean of the property Initial value. The profile list is defined by the parameter hidden_fields_profiles
List A value to select amongst a list of proposed values. These values are defined by the mean of the property Values …
Read-only A value defined in Initial value, and which cannot be modified by anybody
Text A single line of text, which format may be enforced by setting Format
Text area A text with several lines

The tab “Preview” displays a preview of the template as it will be displayed in the console:

 Customized request forms preview

Behavior on the Customer Portal

If a end-user selects a service sub-category on the customer portal which is related to a request template, the specific fields for this template are displayed, grouped under the denomination Service details.

 Customized request form Portal ticket creation

This additional information is copied into the Public log when the User Request is created:

 Customized request form public log

It is also possible for a Support Agent to see or edit the information in the details of the User Request, from the console:

 Customized request form Console ticket creation

Template placeholders

In a notification template, or anywhere else where a template can be used, the following placeholders will be available.

Assuming that this is a UserRequest:

  • $this->service_details$: a plain text representation of the selected values. This is suitable for a plain text email. Though it seems possible to use it within an HTML document, by using a PRE tag, this is NOT recommended because HTML entities (like <) still need to be escaped.
  • $this->html(service_details)$: an HTML representation of the selected values.

Hidden fields are forcibly excluded from the placeholders.

When a template value corresponds to an object selected into iTop, the returned value will be the friendly name of the object.

REST/JSON API

Read and write operations using the REST/JSON API are possible since the 2.4.0 extension version (respectively N°6236 and N°1150), but only if you use iTop 3.1.0 or greater.

Read

To get the request template data, just pick the service_details field in your query. You'll get in the returned JSON the values with :

  • template_id: id for the RequestTemplate object used
  • values:
    • Need: RequestTemplate label
    • one key per field, including the one that were hidden to the user

Example of a returned value:


  1. {
  2. "objects": {
  3. "UserRequest::5": {
  4. "code": 0,
  5. "message": "",
  6. "class": "UserRequest",
  7. "key": "5",
  8. "fields": {
  9. "id": "5",
  10. "title": "Sample UR for JSON read",
  11. "service_details": {
  12. "template_id": 1,
  13. "values": {
  14. "Need": "My RequestTemplate label",
  15. "teststring": "sample text",
  16. "testdate": "2023-04-21"
  17. }
  18. }
  19. }
  20. }
  21. },
  22. "code": 0,
  23. "message": "Found: 1"
  24. }

Write

You'll need to set the corresponding structure to the field you want to set :

  • template_id: id for the RequestTemplate object used
  • values:
    • one key per field, including the one that were hidden to the user

Example of a value to send (json_data payload):


  1. {
  2. "operation": "core/create",
  3. "comment": "New UserRequest with specific request template data",
  4. "class": "UserRequest",
  5. "output_fields": "id, friendlyname",
  6. "fields":
  7. {
  8. "org_id": "SELECT Organization WHERE name = \"Demo\"",
  9. "caller_id":
  10. {
  11. "name": "monet",
  12. "first_name": "claude"
  13. },
  14. "title": "Houston, got a problem!",
  15. "description": "The fridge is empty",
  16. "service_id": 1,
  17. "servicesubcategory_id": 16,
  18. "service_details": {
  19. "template_id": 10,
  20. "values": {
  21. "text": "simple text",
  22. "date": "2023-04-20"
  23. }
  24. }
  25. }
  26. }

Here are the the different error behaviors :

  • template_id value not existing in database: 💣 blocking error
  • template_id value not matching service_id and servicesubcategory_id values: 💣 blocking error
  • field code not existing in the request template : ⚠ the field value isn't saved (but the rest of the query is, and no error is thrown)
  • no value set for a mandatory field : 💣 blocking error
  • invalid value (not part of the possible values) for a list or a drop-down-list field type : 💣 blocking error
  • value set for an hidden field : ⚠ the field value isn't saved (but the rest of the query is, and no error is thrown)
  • value set for a read_only field, different than the initial_value : 💣 blocking error

Questions & Answers

Usage

Q: Performance issues with master field for dependent fields being a text, date or auto-complete list?
A: This is a known limitation which is related to iTop core.

As a workaround, it is recommended to only use as master field a List or Drop-down list with a very limited set of values, so if can be selected in a drop-down and never with auto-complete mode. Do not use as master field, other input type than the recommended ones, as every key stroke in the master field, would generate a reload of the request form, which lead to: blinking, lost of user data entries, performance issue and incorrect display.

Definition: A master field is referenced by at least one other field, within its condition

Reporting

Question: Can I get the UserRequest which do not have a associated Request Template
Answer: Yes & No.

Query like this will fails

 SELECT UserRequest WHERE ISNULL(service_details) = 1

While such query will work, with the limitation that if you have added or removed Request Template to service subcategories after the creation of User Request using those service Subcategories, then the result will be wrong.

SELECT u,rt FROM UserRequest AS u
JOIN ServiceSubcategory AS ss ON u.servicesubcategory_id=ss.id
JOIN RequestTemplate AS rt ON rt.servicesubcategory_id=ss.id
WHERE ISNULL(rt.name) = 1

Question: Can I search for UserRequest which do have a particular value in a field of the associated Request Template
Answer: Yes with a recent enough version (above 2.1.0)

Searching for a value
SELECT UserRequest AS u 
  JOIN TemplateFieldValue AS v ON v.obj_key=u.id
  WHERE v.template_name="Laptop ordering"
    AND field_code='size' 
    AND field_value='wide'

You must specify the name (or id) of the Request Template, as the field_code may not be sufficient to identify uniquely a particular template, the same code could be used on multiple Templates.

You can even get the UserRequest which uses a particular Template having a field which is pointing to an iTop object, and the iTop object is verifying some condition:

  • In that case, the Template Field definition has a Values (OQL or CSV) set with an OQL SELECT Model,
  • we want to set a condition on the remote object, so here get the UserRequest pointing to a Model used for Server class.
Searching for a related object
SELECT u,m FROM UserRequest AS u 
  JOIN TemplateFieldValueLnk AS v ON v.obj_key=u.id
  JOIN Model AS m ON v.field_target_key = m.id
  WHERE v.template_name="Desktop ordering details"
    AND field_code='model' 
    AND field_target_class='Model'
    AND m.type='Server'

TemplateFieldValueLnk is a subclass of TemplateFieldValue, you will need to query that subclass only if you need to set condition on the remote object, otherwise if you just need the value of the model, it is stored in TemplateFieldValue.

Question: Can I search for UserRequest which do have a particular value in a Request Template field and another value in another Request Template field?
Answer: Yes, also it's tricky and as above requires a recent enough version of the extension (above 2.1.0) - Thanks to Synairgis Inc for reporting this limitation

Usecase: Retrieve the UserRequest which have a Request Template named “test” and all those particular values in their Request Template fields:

  • a field with code “profile” must have “1” as its value,
  • and a field with code “contract” having “a” as its value,
  • and a field with code “site” having “Bordeaux” as its value.

Here is the non-working query, followed by the workaround

not working
SELECT UserRequest AS u
JOIN TemplateFieldValue AS v1 ON v1.obj_key=u.id
JOIN TemplateFieldValue AS v2 ON v2.obj_key=u.id
JOIN TemplateFieldValue AS v3 ON v3.obj_key=u.id
WHERE (v1.template_name="test" AND v1.field_code="profile" AND v1.field_value="1")
AND   (v2.template_name="test" AND v2.field_code="contract" AND v2.field_value="a")
AND   (v3.template_name="test" AND v3.field_code="site" AND v3.field_value="Bordeaux")
Working
SELECT UserRequest AS u JOIN TemplateFieldValue AS v1 ON v1.obj_key=u.id
WHERE (v1.template_name="test" AND v1.field_code="profile" AND v1.field_value="1")
  AND u.id IN(
    SELECT UserRequest AS u JOIN TemplateFieldValue AS v2 ON v2.obj_key=u.id 
    WHERE (v2.template_name="test" AND v2.field_code="contract" AND v2.field_value="a")
      AND u.id IN (
        SELECT UserRequest AS u JOIN TemplateFieldValue AS v3 ON v3.obj_key=u.id 
        WHERE (v3.template_name="test" AND v3.field_code="site" AND v3.field_value="Bordeaux")))

Question: Can I get with API REST the request template fields and values for a given UserRequest (id=234)?
Answer: Yes you can, the OQL to use would look like this:

Searching for all values of a request
SELECT TemplateFieldValue
  WHERE obj_class='UserRequest' 
  AND obj_key = '234'

Note: this class is currently limited to Administrator only. But it can be worked around by creating your own REST service.

Question: Can I display in an Attribute overview, the UserRequests referencing the current object?
Answer: Yes you can, the OQL to use in the Dashlet would be based on this one, with additional criterion to filter further if required:

Search from a remote object
SELECT UserRequest AS u JOIN TemplateFieldValueLnk AS l ON l.obj_key = u.id 
  WHERE obj_class='UserRequest' 
  AND field_target_class = :this->finalclass
  AND field_target_key = :this->id

Question: I have installed version 2.1, but OQL queries does not return old User Request.
Answer: With version 2.1.0 or above of this extension, if you want to perform queries over User Requests made prior to the deployement of this version, you have to launch once, a cli script which will explode the data created before into the new queryable objects.

The command requires to be on iTop server using the web user:

cd /path/to/itop/
cd env-production/templates-base/
php populateTemplateFieldValue.php --append

This command explodes not-yet-exploded CustomAttribute data into new objects TemplateFieldValue and TemplateFieldValueLnk.

Note: An alternate mode is php populateTemplateFieldValue.php –reset which empty the new tables and rebuild them from scratch. Just after the upgrade to 2.1, the 2 modes are pretty similar.

Always run this kind of heavy script on your integration environment first, with a copy of your production data
You should run this command with your webserver user, otherwise you may have difficulties to access cache files inside data/cache-production/

User Portals

Question: I want to install this extension on my own portal, how can I do it?
Answer: It requires to write an iTop extension. Add the below XML to the creation Form of the UserRequest in your own portal

itop_design / module_designs / module_design@my-itop-portal / forms
  <form id="ticket-create">
    <twig>
     <div class="form_field" data-field-id="service_details"/>

Here I suppose that the id of the Ticket creation form is called “ticket-create” but any id is possible, the important piece is the data-field-id which must be exactly service_details.

Question: I have installed this extension on an iTop without itop-portal and service_details cannot be edited. Why?
Answer: That's an historical trick related to the old itop portal prior to version 2.3.0. Here is what the extension does:

itop_design / classes / class@UserRequest / lifecycle
  <states>
    <state id="new">
      <flags>
        <!-- If the modern portal is NOT installed, the custom fields will remain Read-Only -->
        <!-- Otherwise, the module itop-request-template-portal will enable the field in RW mode -->
        <attribute id="service_details" _delta="define">
          <read_only/>
        </attribute>
      </flags>
    </state>
  </states>

to fix this you must alter the datamodel of the extension (so after it) in another extension.

itop_design / classes / class@UserRequest / lifecycle
        <states>
          <state id="new">
            <flags>
              <attribute id="service_details" _delta="delete"/>
            </flags>
          </state>
        </states>

On "Change" class?

Question: I want to define RequestTemplate on the “Change” class. Can I do it?
Answer: Yes, but it requires to write an iTop extension.

We assume that you have installed your iTop with “Change Simple”. It's possible to do it even on full ITIL, but a bit more complex

What is required:

  1. Add fields service_id and servicesubcategory_id to the class Change
  2. Add field service_details to the class Change
  3. Adapt presentation of the class Change to display the 3 above fields
  4. Change ServiceSubcategory request_type field to include “change” as a valid value
  5. Customize the RequestTemplate method GetTargetClass() to return “Change” when appropriate
  6. Change servicesubcategory_id filter on class UserRequest to not propose change related Service Subcategories

1) You will have to associate your Change to a Service and a Service Subcategory, as it is the ServiceSubcategory which is the link to retrieve the possible RequestTemplates applicable to an object. It is possible to do without this assumption but it's way more complex and won't be explained at all.
Check here if you don't know how to add those fields service_id and servicesubcategory_id to the class Change

itop_design / classes / class@Change / fields
  <field id="servicesubcategory_id" xsi:type="AttributeExternalKey" _delta="define">
    <sql>servicesubcategory_id</sql>
    <is_null_allowed>true</is_null_allowed>
    <on_target_delete>DEL_MANUAL</on_target_delete>
    <target_class>ServiceSubcategory</target_class>
    <filter>SELECT ServiceSubcategory WHERE request_type='change'</filter>
  </field>

2) you will have to add this very particular field.

itop_design / classes / class@Change / fields
  <field id="service_details" xsi:type="AttributeCustomFields" _delta="define">
      <handler_class>RequestTemplateFieldsHandler</handler_class>
  </field>

3) Of course, you need to redefine the presentation to add those 3 fields to the display of a Change object in the Console

itop_design / classes / class@Change
<presentation>
  <details>
    ...

If you also have added the Change object to a portal refer to the above question for adding the request template as well on your Change in your Portal.

4) Add a change value to the Service Subcategory class, so you can flag in your Service catalog, the Subcategory which are applicable to Change:

itop_design / classes / class@ServiceSubcategory / fields
  <field id="request_type" _delta="if_exists">
    <values>
      <value id="change" _delta="define">change</value>
    </values>
  </field>

5) Redefine the RequestTemplate::GetTargetClass() method by the one below or something similar

class:RequestTemplate
public function GetTargetClass()
{
   $iSubCategory = $this->Get('servicesubcategory_id');
   $oSubCategory = MetaModel::GetObject('ServiceSubcategory', $iSubCategory);
   if (is_null($oSubCategory))
   {
      throw new Exception('Missing Service Subcategory');
   }
   $sRequestType =$oSubCategory->Get('request_type');
   if (($sRequestType == 'change') && (class_exists('Change')))
   {
      return 'Change';
   }
   if (($sRequestType == 'incident') && (class_exists('Incident')))
   {
      return 'Incident';
   }
   if (class_exists('UserRequest'))
   {
      return 'UserRequest';
   }
   throw new Exception("The selected Service Subcategory is incompatible with 
      your installation options (request type '$sRequestType' not supported)");
}

6) Portal adaptation
You may adapt this method to enable a Change creation on iTop Portal upon selection of a ServiceSubcategory related to a Change.
That's not enough, as you will need to add scopes, forms and maybe brick to manage correctly the Change in the Portal, but this is another topic.

class:Ticket
static public function CreateFromServiceSubcategory($oServiceSubcategory)
{
   $sType = $oServiceSubcategory->Get('request_type');
   if ($sType == 'change')
   {
      if (!class_exists('Change'))
      {
         throw new Exception('Could not create a ticket after the service '
             .$oServiceSubcategory->Get('friendlyname').' of type '.$sType
             .': unknown class "Change"');
      }
      $oRet = new Change();
   }
   elseif ($sType == 'incident')
   {
      if (!class_exists('Incident'))
      {
         throw new Exception('Could not create a ticket after the service '
             .$oServiceSubcategory->Get('friendlyname').' of type '.$sType
             .': unknown class "Incident"');
      }
      $oRet = new Incident();
   }
   else
   {
      if (!class_exists('UserRequest'))
      {
         throw new Exception('Could not create a ticket after the service '
             .$oServiceSubcategory->Get('friendlyname').' of type '.$sType
             .': unknown class "UserRequest"');
      }
      $oRet = new UserRequest();
   }
   return $oRet;
}

Request Template per Service?

Question: I want to define RequestTemplate on the “Service” instead of the Service Subcategory. Can I do it?
Answer: Yes, but it requires to write an iTop extension.

Here we propose to define RequestTemplate per Service, but you could imagine to do it per Organization, Priority or any combination of UserRequest fields

1) Customize RequestTemplate, to remove the field servicesubcategory_id and create a service_id ExternalKey field

itop-design / classes / class@RequestTemplate / fields
    <field id="servicesubcategory_id" _delta="delete"/>
    <field id="service_id" xsi:type="AttributeExternalKey" _delta="define">
       <filter><![CDATA[SELECT Service AS s WHERE s.status != 'obsolete']]></filter>
       <dependencies/>
       <sql>service_id</sql>
       <target_class>Service</target_class>
       <is_null_allowed>false</is_null_allowed>
       <on_target_delete>DEL_AUTO</on_target_delete>
       <allow_target_creation>false</allow_target_creation>
    </field>

Modify the presentation as well… to reflect this change of field

2) Create a new TemplateFieldsHandler sub-class to change the way the applicable RequestTemplate are retrieved

class MyTemplateFieldsHandler extends TemplateFieldsHandler
{
        /**
         * @return DBObjectSet of Templates
         */
        protected function FindTemplates(DBObject $oHostObject)
        {
                $oSearch = DBSearch::FromOQL('SELECT RequestTemplate WHERE service_id= :criteria');
                $oSet = new DBObjectSet($oSearch, array(), array('criteria' => $oHostObject->Get('service_id')));
                return $oSet;
        }
}

3) Change UserRequest service_details field to use the new TemplateFieldsHandler sub-class

itop-design / classes / class@UserRequest / fields
    <field id="service_details" xsi:type="AttributeCustomFields" _delta="must_exist">
       <handler_class _delta="redefine">MyTemplateFieldsHandler</handler_class>
    </field>

Values not refreshed

Question: When I define possible values which depends on xxx_name which is a Ticket field, it does not refresh.
Answer: Yes, this is a known limitation. team_name is an ExternalField, it's not a user provided field, it is computed based on another user provided one, here team_id. Because of an iTop limitation (still present in 3.0) dependencies on such type of field does not work. The list is not refreshed, when that field is modified. There is a workaround, also it makes the query writing a bit more complex sometimes.

First usecase: let's assume that you want to display the servers linked to the Ticket Team
Here is the non-working version followed by the workaround

Non working version
SELECT Server AS s JOIN lnkContactToFunctionalCI AS l ON l.functionalci_id=s.id 
  WHERE l.contact_name=:this->team_name
Working version
SELECT Server AS s JOIN lnkContactToFunctionalCI AS l ON l.functionalci_id=s.id 
  WHERE l.contact_id=:this->team_id

Second usecase: let's assume that you want to display the servers belonging to the organization of the Ticket Team
and that you have created a new ExternalField on UserRequest called teamorg_id computed as the organization id of the team

itop-design / classes / class@UserRequest / fields
        <field id="teamorg_id" xsi:type="AttributeExternalField" _delta="define">
          <extkey_attcode>team_id</extkey_attcode>
          <target_attcode>org_id</target_attcode>
        </field>

Here are the non-working version followed by the workaround

Non working version
SELECT Server AS s WHERE s.org_id=:this->teamorg_id
Working version
SELECT Server AS s JOIN Organization AS o ON s.org_id=o.id JOIN Contact AS c ON c.org_id=o.id 
  WHERE c.id=:this->team_id

Wrong History

Question: When “service_details” is editable, every ticket edition stores a modification of that field also it was not modified
Answer: This is a known issue, which should be fixed one day, for now, you can stop all history tracking on that field if you wish:

itop-design / classes / class@UserRequest / fields
    <field id="service_details" xsi:type="AttributeCustomFields" _delta="must_exist">
       <tracking_level _delta="force">none</tracking_level>
    </field>
extensions/request-templates.txt · Last modified: 2024/10/24 12:22 by dflaven
Back to top
Contact us