2The Plug-In Framework

Basics of the Plug-In Framework

Oracle Field Service Cloud is a highly developed application that can be customized for the unique purposes and specialized business needs of organizations. That extensibility is achieved in part through the use of plug-ins, which can perform actions not found in the standard solution. Plug-ins appear as selectable links on the application. They open a new window, tab, or frame in a browser where an external HTML5 application is executed.

Plug-ins can be internal or external. Internal plug-ins affect the behavior of the Oracle Field Service Cloud platform and can modify objects stored in the database. They use the internal structures of the application and can work in the offline mode with Mobility Cloud Service. They can be created only by Oracle developers. External plug-ins, however, can be developed by anyone; they use externally stored data and communicate with the application by HTTP requests. The external plug-ins use HTML5 features such as offline work and persistence storage. The plug-in framework also allows these applications to exchange data with Oracle Field Service Cloud, in two ways:
  • Traditional one-way communication when the plug-in receives data from OFSC via HTTP GET and POST parameters.

  • Two-way communication using Oracle Field Service Cloud Plug-in API

The plug-in framework offers the following features:
  • Integration with Oracle Field Service Cloud through an API and, therefore, the ability to perform complex tasks which could previously be performed only by internal plug-ins

  • Ability to work offline with Mobility Cloud Service

  • Plug-in development by your organization or third-party developers without requiring Oracle developers

The plug-ins work in Oracle Field Service Mobility Cloud Service and can manipulate the following Oracle Field Service Cloud entities:
  • Resource

  • Activity

  • Inventory (does not include Parts Catalog)

  • Activity list

  • Inventory list

Consequently, the plug-ins can be added to the following Mobility Cloud Service contexts:
  • Activity list

  • Edit/View activity

  • Inventory grid

  • Add/Details inventory

Requirements to Use a Plug-In API

This topic provides the requirements to develop a plug-in for Oracle Field Service Cloud.

You must meet these requirements to develop a plug-in using the plug-in API:
  • The plug-in URL must point to the main page of the plug-in source and use the HTTPS protocol. The main page must be accessible through the configured plug-in URL.

  • The main page must be a valid HTML/XHTML page that can load JavaScript code sources, static resources (images, .css style sheets ), or contain them directly.

  • A valid offline plug-in must run JavaScript code in the main page interacting with Mobility Cloud Service.

  • To make the plug-in accessible in the offline mode, the <html> tag should contain a manifest attribute whose value points to a file of the special offline manifest format describing what resource files must be cached by the browser for offline. The offline plug-in is processed entirely outside of Oracle Field Service Cloud.

  • You can also load resources for offline plug-in using Service Workers. However, you must be aware of their availability in different versions of browsers.

  • The plug-in can save data for offline use locally on the user’s device by means of cookies, local storage, or indexed DB.

  • The plug-in is loaded into an iframe. The URL points outside the Oracle Field Service Cloud domain, therefore its application cache, cookies, local storage, and indexed DB are separated from those of the application and cannot interfere with them according to the Same origin policy. Most properties of the parent window are also unavailable for plug-in JavaScript code. As a result, the only way to interact with Mobility Cloud Service is through the plug-in API.

  • It’s required to use a valid certificate, not a self-signed certificate.

  • The ability to work offline must be maintained by the plug-in developer. Oracle Field Service Cloud only provides the ability to load all plug-in files on start, by opening the plug-in in an invisible iframe. The plug-in developer must take care of the application cache state and use the plug-in properly in offline mode.

Placeholders used in the URL

You can include the following placeholders in the URL to send additional parameters to the plug-in:
  • {user_id }, {uid}: ID of the current user

  • {date}: Current date

  • {timestamp}: Current timestamp in ISO format

  • {uname}: User name

  • {ulanguage}: ID of the user 's language

  • {ulogin}: User login

  • {su_zid}: User timezone

  • {allow_desktop_notifications}: Parameter defining whether the user allows HTML5 notifications

  • {allow_vibration}: Parameter defining whether the user allows vibration alerts

Using HTTPS

The plug-in must be hosted on an HTTPS server. If your web server is not configured to use HTTPS, follow your web server documentation and configure it. Further, ensure that the plug-in is hosted on the same port as Oracle Field Service Cloud, which is port 443.

Basic HTTP Authentication

The basic HTTP authentication method is a standard method, which is part of the HTTP 1.0 standard ( RFC 1945) called Basic Access Authentication. It works over HTTPS as well.

Ensure that the following conditions are met:
  • Oracle Field Service Cloud: In the Add action link and Edit action link windows, select HTTP Basic authentication type, and fill up the Login and Password fields with valid values. These credentials are encrypted and saved to the Oracle Field Service Cloud database.

  • Server Side: Configure the web server on which the plug-in sources are hosted to return the HTTP 401 Unauthorized status, if you are requesting the configured plug-in URL without the credentials. See the NGINX and Apache documents for details. The server must return the plug-in content if its URL is requested with the HTTP header. Authorization: Basic bXlsb2dpbjpteXBhc3M= Where bXls ... is a valid Base64 - encoded pair of login:password. The credentials configured for the plug-in in the Add action link and Edit action link windows must be accepted as valid.

  • Client Side: When the user logs in to Mobility Cloud Service, Oracle Field Service Cloud reads the credentials from the database and loads the plug-in URL into the hidden iframe as follows: <iframe src="https://mylogin:mypass@example.com/myPlugin.php"/> This way, the browser loads the plug-in sources over HTTPS using HTTP Basic Authentication:
    GET /myPlugin.php HTTP/1.1
    Host: example.com
    Authorization: Basic bXlsb2dpbjpteXBhc3M=
Note: We recommend that you use HMAC authentication instead of basic HTTP authentication. This is because, Google Chrome doesn’t support the use of Basic HTTP authentication in sub-resources starting from release 59.

HMAC Authentication

HMAC (Hash - based message authentication code) lets you sign HTTP requests and their GET parameters. It authenticates to see that the data is not forged and is not received from an unauthorized source.

The MAC signature (digest) is added as an additional GET parameter at the end of query string: <!CDATA[[http://www.example.com/path?user=test&section=D%26G&activity=33&hmac=D2BJn9P1EcLhaFrNhbAzCQTVQXCCwCBQsrg8V6h4YoU%3D]]>.

HMAC function algorithm

The algorithm is defined in RFC 2104 , and can be very roughly described as: hmac = BASE64(HMAC - SHA - 256(data, SHA256(SecretKey))). SHA - 256 accepts SecretKey as a string and returns the hash string. The secret key is configured per plug-in in the Add action link and Edit action link windows in Core Manage Cloud Service, hashed by SHA256, encrypted and stored in the database. HMAC-SHA-256 accepts data and key as strings and returns a binary array of HMAC signature. BASE64 accepts the binary array and returns BASE64 encoded string. Data for HMAC generation is query resource location with query parameters sorted lexicographically:
  • Remove the protocol identifier from the URL together with colon and slashes ( http:// or https:// ).

  • Remove the resource name and port from the URL.

  • Append query location to the output string.

  • If there are query parameters append the character ? to the output string.

  • Decode every name and value for URL parameters.

  • Sort the list of parameters alphabetically by name.

  • For each name/value pair:

    • Append the encoded name to the output string.

    • Append the ‘=’ character to the output string.

    • Append the encoded value to the output string.

  • If there are more key/value pairs remaining, append an & character to the output string.

Example: Request URL: http://www.example.com/path?user=test&section=D%26G&activity=33
SecretKey : 'mysecret'
  1. http://www.example.com/path?user=test&section=D%26G&activity=33 => www.example.com/path?user=test&section=D%26G&activity=33

  2. www.example.com/path?user=test&section=D%26G&activity=33 => /path?user=test&section=D%26G&activity=33

  3. data = '/path'

  4. data = '/path?'

  5. ['user'='test','section'='D&G','activity'=33]

  6. ['activity'=33,'section'='D&G','user'='test']

  7. ['activity'=33,'section'='D&G', 'user'='test'] => data

  8. data = '/path? activity'

  9. data = '/path? activity='

  10. data = '/path? activity=33'

  11. data = '/path? activity=33&'

  12. data = '/path? activity=33&section=D %26G&user=test'

hmac = BASE64(HMAC-SHA-256('/path?activity=33&section=D%26G&user=test',SHA256('mysecret'))) = BASE64(HMAC - SHA - 256( '/path? activity=33&section=D %26G&user = test' ,'652c7dc687d98c9889304ed2e408c74b611e86a40caa 51c4b43f1dd5913c5cd0')) = BASE64([0f,60,49,9f,d3,f5,11,c2,e1,68,5a,cd,85,b0,33,09,04,d5,41,70,82,c0,20,5 0,b2,b8,3c,57,a8,78,62, 85]) = 'D2BJn9P1EcLhaFrNhbAzCQTVQXCCwCBQsrg8V6h4YoU='

The full signed URL is 'http://www.example.com/path?user=test&section=D%26G&activity=33&hmac=D2BJn9P1EcLhaFrNhbAzC QTVQXCCwCBQsrg8V6h4YoU%3D'

Plug-In API Specification

The plug-in API is based on cross-window messaging with postMessages, which can be sent by Oracle Field Service Cloud and received by the plug-in and vice-versa. Messages are sent by JavaScript code using window.postMessage() method, and received by subscribing to messages using window.addEventListener().

Message format

The following message format is supported:window.frames['my_plugin'].postMessage('{"apiVersion": 1,"method": "open","entity":"activity","resource":{"pid": 5000038}}", targetOrigin);

Message processed by the plug-in:
function getPostMessageData(event)
{
    var data = JSON.parse(event.data);
    switch (data.method)
    {
        case 'open':
            pluginOpen(data);
        break;
        default:
            showError();
    }
};
window.addEventListener("message", _getPostMessageData, false);
JSON data is an object (hash) of defined format containing special fields (which describe the message itself) and data fields (which contain the data of Oracle Field Service Cloud entities), for example:
{
    "apiVersion": 1,
    "method": "open",
    "entity": "activity",
    "resource": {
        "pid": 5000038
    },
    "inventories": {
        "20997919": {
            "invid": 20997919,
            "inv_pid": 5000038,
        }
    }
}
where:
  • apiVersion, method , entity – special fields

  • resource, inventories – entity data collections available only for the 'open' and 'close' methods

Special fields:
  • apiVersion – version of the plug-in API used for interaction between Mobility Cloud Service and the plug-in. It defines the available methods and data

  • method – describes the action initiated by Oracle Field Service Cloud or the plug-in and the actions to be performed on the other side

  • entity – name of the Oracle Field Service Cloud entity to be processed by the plug-in

Messages for the ready and error methods have a different list of available fields.

Available Methods

Methods initiated by Oracle Field Service Cloud

The methods initiated by Oracle Field Service Cloud are:
  • init: Notifies the plug-in that it should perform initialization. For example, load metadata or offline files from the server.

  • open: The plug-in content is to be shown on the Mobility Cloud Service screen.

  • error: The data submitted by the plug-in is invalid or internal errors have occurred.

  • wakeup: Notifies the plug-in about the presence of network connectivity. The plug-in can perform its own synchronization after receiving this message.

Methods initiated by the plug-in

The methods initiated by the plug-in are:
  • ready: The plug-in has been loaded and is ready to receive messages.

  • initEnd: The plug-in notifies Oracle Field Service Cloud that it has finished initialization and can be suspended until opened by the user.

  • close: The plug-in submits data after which its window will be closed if the data is valid.

  • sleep: If the plug-in is not able to synchronize with its own server due to absence of network connectivity, it can notify Oracle Field Service Cloud to wake it up in the background when connectivity is available.

Initialization

The following figure shows the flow of steps in initializing a plug-in:
  • Create an iframe, if required

  • Execute the ready method

  • Execute the init method

  • Execute the initEnd method; here, the wakeupNeeded parameter is set to ‘true’

  • Destroy the iframe, if it is created


This figure shows the steps in initializing the plug-in.

ready Method

ready Method

These messages are always sent in the following format:
{
    "apiVersion": 1,
    "method": "ready"
}
The optional “dataItems” field can be included in the message to limit the amount of data sent to plug-in in open method. See “Limit the amount of data sent to the plug-in” for more details.

Limit the Amount of Data Sent to the Plug-In

Mobility sends all data available for entity collections, with the "open" message. The data is sent according to the layout, where the plug-in's action link is placed and visibility of properties on plug-in API layouts. This means that when plug-in is opened from Activity List screen, the data of all activities for selected day's queue will be sent with the data of all non-scheduled activities of selected resource. To reduce the amount of data collected and serialized by Mobility and un-serialized by a plug-in, the new optional parameter dataItems is added for the "ready" message. This decreases loading time of the plug-in. The value of this parameter defines which items are present in the entity collections. Using this parameter the plug-in can prevent Mobility from sending certain items in available entity collections, but it can't broaden the set of entity collections sent to the plug-in. This set is predefined and depends on the screen from which the plug-in is opened.

Hiding the Header When the Plug-In is Open

When a user opens a plug-in, it is shown in Oracle Field Service Mobility Cloud Service and the header of the screen is rendered by Oracle Field Service Cloud. The user can exit the plug-in by clicking Back in the header. The plug-in will be closed without sending any data to Oracle Field Service Cloud. In some business flows, it is preferred to hide the header of the screen so that the plug-in can:
  • Render the header itself

  • Based on the business flow, decide whether the user can leave the plug-in

To support this function, the "ready" method is extended, and a new flag, "showHeader" is added:
  • If flag value is set to TRUE, then the Oracle Field Service Mobility Cloud Service header is shown.

  • If flag value is set to FALSE, then the Oracle Field Service Mobility Cloud Service header is hidden.

Preventing the User from Using Back

When a user opens a plug-in, it is shown in Oracle Field Service Mobility Cloud Service and the header of the screen is rendered by Oracle Field Service Cloud. The user can exit the plug-in by clicking Back in the header or the browser. The plug-in will be closed without sending any data to Oracle Field Service Cloud. In some business flows, it is preferred to prevent the user from returning using any of the options. Based on the business flow, the plug-in decides whether the user must exit the plug-in or not. To support this function, the "ready" method is extended, and a new flag, "enableBackButton" is added:
  • If flag value is set to TRUE, then the Oracle Field Service Mobility Cloud Service Back button is shown and the navigation is not locked.

  • If flag value is set to FALSE, then the Oracle Field Service Mobility Cloud Service Back button is hidden and the navigation is locked. This means, the browser's native Back and Forward buttons are disabled.

Example for ready Method

// the header is shown but the "back" button is hidden:
{
    "apiVersion": 1,
    "method": "ready",
    "showHeader": true,
    "enableBackButton": false
}
   
// the header is hidden but the user can go back using browser's back button:
{
    "apiVersion": 1,
    "method": "ready",
    "showHeader": false,
    "enableBackButton": true
}
  
// the header is hidden and the user can leave the plugin only when the plugin sends the "close" message via Plugin API (the browser's back button does not work):
{
    "apiVersion": 1,
    "method": "ready",
    "showHeader": false,
    "enableBackButton": false
}

Plug-In Action Flow

This topic describes the flow of the plug-in, when a user opens it to perform an action.

The following figure describes the flow of the plug-in, when a user opens it to perform an action:
This figure shows the main flow of the plug-in.
The flow of steps is as follows:
  • The user clicks the action link in Oracle Field Service Mobility Cloud Service.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Open method is executed.

  • The Close method is executed; here, the wakeupNeeded parameter is set to ‘true’.

  • The iframe is destroyed, if it is created.

Available Entities and Data Collections

The 'entity' field and entity data collections are available only for methods 'open' and 'close'. The value of the special 'entity' field depends on the Oracle Field Service Mobility Cloud Service screen on which the plug-in is used. The availability of entity data collections sent within the message data depends on the value of 'entity'.

The following table describes the entities and the data collections available for them:

Screen Entity Field Value Available Collections
Activity List activityList
  • resource

  • activityList

  • inventoryList

Activity List > Inventory List inventoryList
Activity List > Activity Details activity
  • resource

  • activity

  • inventoryList

Activity List > Activity Details> Inventory List activityInventoryList
Activity List > Inventory List > Inventory Details inventory
  • resource

  • activityList

  • inventory

Activity List > Activity Details > Inventory List > Inventory Details activityInventory
  • resource

  • activity

  • inventory

Note: Resource properties cannot be set or updated through the plug-in API. Resource collection is intended to show additional information in the plug-in.
Entity data collections
  • resource – element in the resource tree representing a defined company asset

  • activity – entity of Oracle Field Service Cloud that represents any time-consuming activity of the resource

  • activities – activity list

  • inventory – equipment that can be installed or de-installed during an activity

  • inventories – inventory list

File Properties Support

The "close" method is extended with the support of file properties. The file properties can be sent both through data collections and through actions. Due to performance limitations, it's not rational to send the file contents using JSON strings, so the plug-in API now accepts raw JS objects as values for PostMessage data. The original JSON strings are still supported, so backward compatibility with existing plug-ins framework implemented in release 17.2 is retained, but the file properties cannot be updated in this case.

The value of each file property must be an object that has two fields:
  • fileName - name of the file, which is shown on the user interface

  • fileContents - Blob object, which contains the file contents. It can be constructed and filled with the generated data by JS code in runtime, or just obtained from file input and sent to Oracle Field Service Mobility Cloud Service without any transformation, as the File object inherits the Blob.

The file can be deleted by setting the appropriate property to empty string or null.
Note: The Image property lets you to set the coordinates through the Oracle Field Service Mobility Cloud Service interface, but there is no support for setting the coordinates in the image property in the plug-in API.

Example: How to Send the Uploaded File

var file = document.querySelector('input[type=file]').files[0];
   
window.parent.postMessage
(
    {
        apiVersion: 1,
        method: 'close',
        activity:
        {
            ccity: 'Cleveland',
            door_photo:
            {
                fileName: 'DCIM_20170425_203115.jpg',
                fileContents: file
            }
        }
    },
    targetOrigin
);

Example: How to Send the Generated File Contents

var text =
    '<?xml version="1.0" encoding="UTF-8"?>' +
    '<test></test>';
  
var blob = new Blob([text], { type: 'text/xml' });
   
window.parent.postMessage
(
    {
        apiVersion: 1,
        method: 'close',
        activity:
        {
            ccity: 'Cleveland',
            XML_DATA_PROP:
            {
                fileName: 'test_data.xml',
                fileContents: blob
            }
        }
    },
    targetOrigin
);

Example: How to Delete a File

window.parent.postMessage
(
    {
        apiVersion: 1,
        method: 'close',
        activity:
        {
            file_property: ''
        }
    },
    targetOrigin
);

Order of Execution of Actions

Actions are applied in the same order, as sent in the "actions" array of the plug-in. Actions are executed after applying of all data collection updates that are sent by plug-in in the same "close" message. No actions are applied if there are errors during the validation of data collections and the actions that are sent by the plug-in. All validation errors are sent to the plug-in within the "error" message. If some actions fail to execute, the remaining actions are applied, and the execution errors are sent to the plug-in within the "error" message.

Each error contains the ID of the action that has failed or that doesn't pass validation. ID is the order number of the action in the actions list, sent by plug-in. So, Oracle Field Service Mobility Cloud Service processes the "close" message as follows:
  1. Validate entity data collections.

  2. Validate actions.

  3. If there are any validation errors, send an "error" message to the plug-in; otherwise proceed to the next step.

  4. Apply data collections update.

  5. Apply actions.

  6. If there are any errors, occurred during update of data collections or execution of actions, send "error" message to a plug-in; otherwise proceed to the next step.

  7. Close the plug-in window.

Action Parameters

Each action is an object, whose fields are the action parameters. Every action must contain at least two fields (parameters):
  • entity - must be equal to "inventory"

  • action - must be equal to one of the supported inventory actions (e.g. "install", "create")

Parameters that are specific to each action are described in the section Supported inventory actions.
Note: Parameters that contain the ID of entities (invid, inv_aid, inv_pid) are of the type "string" and not "number". This is because, entities created on the client side have the IDs similar to "1234567890-1234" before they're synchronized with the server.
Labels and values of all parameters are case-sensitive, for example, all these parameters are invalid:
{
    ACTION: "INSTALL"
    entity: "Inventory",
    Inv_Aid: ""
}

Creating and Deleting Inventory

Usually inventory data is updated by a plug-in using data collections such as "inventoryList" and "inventory" of the Close method. It is not possible to create or delete inventories using data collections. You can do it using the optional field Actions added to the Close method. The plug-ins support the following actions:
  • Install

  • Deinstall

  • Undo install

  • Undo deinstall

  • Create

  • Delete

Each action is an object, and its fields are the action parameters. Every action must contain at least two fields (parameters)—entity and action. Entity must be inventory and action must include one of the actions mentioned earlier.
Format of the dataItems parameter: The dataItems parameter is an array where each item is a label of a certain data subset. If the item with the label of a subset is absent in the array, then Mobility will not send the corresponding items in the entity collections of the "open" message. If the dataItems parameter is not set in the "ready" message, no filtering is applied and full data set is sent to the plug-in. The following table provides the available keys and data subsets:

Key Affected Collections Description
resource resource Properties of the currently selected resource
scheduledActivites activityList Activities, scheduled (belongs to the queue) for the selected date
nonScheduledActivites activityList Non-scheduled activities, that do not belong to any date's queue
resourceInventories inventoryList Inventories in the "provider" pool
installedInventories inventoryList Inventories in the "install" pool
deinstalledInventories inventoryList Inventories in the "deinstall" pool
customerInventories inventoryList Inventories in the "customer" pool

Support for Non-Serialized Inventory

You can install or de-install non-serialized inventory such as cable or faceplates through plug-in APIs. You can perform the following actions with non-serialized inventory:
  • Create an inventory assigned to a resource

  • Create a customer inventory linked with a specific activity

  • Create an inventory in the "installed" pool

  • Create an inventory in the "deinstalled" pool

  • Delete inventory

When non-serialized inventory such as 10 feet (or 10 meters) of cable is installed, depending on whether the inventory of the same type has been installed before, the plug-in API performs the following steps:
  • If there is no inventory of the same type (or type and model, depending on the configuration) in the "installed" pool, then it is created and the quantity is set to the amount installed, for example, 10.

  • If installed inventory exists, it is updated and it's quantity is increased by the amount installed. For example, there is 20 feet (or 20 meter) of cable already installed, then the total amount is set to 30.

The same steps are performed when you de-install inventory.

Supported Inventory Actions

Install: The following table describes the parameters for the install inventory action:

Param Name Mandatory Type Description
invid Yes String ID of the existing inventory that is in the "provider" pool of the current resource or their teammates.
inv_aid Yes String ID of the started activity. Inventory will be installed to its "install" pool. Must contain the ID of the started segment for multi-day activities.
quantity Yes/No Number
  • Is mandatory and must be > 0 for non-serialized inventory types.

  • Is forbidden for serialized inventory types.

properties No Object
  • Is a key-value object, where keys are the labels of inventory properties to be updated.

  • Properties are validated and processed according to the Inventory properties for Mobility layout of the logged in user's User Type. So, properties that you want to update must be added to this layout and the Read/Write or Mandatory visibility must be set.

De-install: The following table describes the parameters for the de-install inventory action:

Param name Mandatory Type Description
invid Yes String ID of the existing inventory that is in the "customer" pool of the current resource or their teammates.
inv_pid Yes String ID of the current resource or their teammates. Inventory will be de-installed to its "deinstall" pool.
quantity Yes/No Number
  • Is mandatory and must be > 0 for non-serialized inventory types

  • Is forbidden for serialized inventory types

properties No Object
  • Is a key-value object, where keys are the labels of inventory properties to be updated.

  • Properties are validated and processed according to the Inventory properties for Mobility layout of the logged in user's User Type. So, properties that you want to update must be added to this layout and the Read/Write or Mandatory visibility must be set.

Undo-install: The following table describes the parameters for the undo install inventory action:

Param name Mandatory Type Description
invid Yes String ID of the existing inventory that is in the "install" pool of the started activity.
quantity Yes/No Number
  • Is mandatory and must be > 0 for non-serialized inventory types

  • Is forbidden for serialized inventory types

properties No Object
  • Is a key-value object, where keys are the labels of inventory properties to be updated.

  • Properties are validated and processed according to the Inventory properties for Mobility layout of the logged in user's User Type. So, properties that you want to update must be added to this layout and the Read/Write or Mandatory visibility must be set.

Undo-deinstall: The following table describes the parameters for the undo-deinstall inventory action:

Param name Mandatory Type Description
invid Yes String ID of the existing inventory that is in the "de-install" pool of the current resource or their teammates.
quantity Yes/No Number
  • Is mandatory and must be > 0 for non-serialized inventory types.

  • Is forbidden for serialized inventory types.

properties No Object
  • Is a key-value object, where keys are the labels of inventory properties to be updated.

  • Properties are validated and processed according to the Inventory properties for Mobility layout of the logged in user's User Type. So, properties that you want to update must be added to this layout and the Read/Write or Mandatory visibility must be set.

Create: The following table describes the parameters for the create inventory action:

Param name Mandatory Type Description
invtype Yes String Label of one of the configured Inventory Types, for example "NT".
invpool Yes String Inventory pool in which the inventory will be created. It is one of: "customer", "install", "deinstall", and "provider".
inv_aid Yes/No String
  • ID of the started activity. Inventory will be created in its pool. Must contain the id of started segment for multi-day activities.

  • Is mandatory if invpool is one of: "customer", "install", "deinstall".

  • Is forbidden for invpool equal to "provider".

inv_pid Yes/No String
  • ID of the current resource or their teammates. Inventory will be created in the resource’s pool.

  • Is mandatory if invpool is one of: "provider", "install", "deinstall".

  • Is forbidden for invpool equal to "customer".

quantity Yes/No Number
  • Is mandatory and must be > 0 for non-serialized inventory types

  • Is forbidden for serialized inventory types

Note: When quantity is not present in the screen configuration Plugin API > Inventory properties for Mobility or is present and set to Read only, then it is set to "1" for non-serialized inventory by Oracle Field Service Mobility Cloud Service.
properties No Object
  • Is a key-value object, where keys are the labels of inventory properties to be updated.

  • Properties are validated and processed according to the Inventory properties for Mobility layout of the logged in user's User Type. So, properties that you want to update must be added to this layout and the Read/Write or Mandatory visibility must be set.

Delete: The following table describes the parameters for the delete inventory action:

Param name Mandatory Type Description
invid Yes String Id of the existing inventory that is in the "provider" pool of the current resource or their teammates or in "install", "deinstall" or "customer" pool of the started activity. The quantity parameter is not available for the Delete action. The entire record with any quantity will be deleted from the selected pool.

Returning from the Plug-In

The "close" method allows a plug-in to define the screen to which the user is redirected to, after executing this method. The behavior is controlled by the "backScreen" parameter.

Previously, there were four possible values for this parameter:
  • default - the user is redirected to the screen that was opened before the plug-in was opened. For example, if plug-in was open from the activity list then the user is redirected back to the activity list

  • activity_by_id - the user is redirected to the activity details of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • next_activity - the user is redirected to the activity details of the next pending activity in the list. If it is not possible to do then the user is redirected to the activity list

  • activity_list - the user is redirected to the activity list

Now, the list of possible values has been extended to:
  • start_activity - the user is redirected to the "start activity" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • end_activity - the user is redirected to the "complete activity" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • cancel_activity - the user is redirected to the "cancel activity" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • notdone_activity - the user is redirected to the "not done" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • suspend_activity - the user is redirected to the "suspend activity" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

  • delay_activity - the user is redirected to the "suspend activity" screen of the activity that is identified by the id set in the parameter "backActivityId". If it is not possible to do then the user is redirected to the activity list

Caution: Both Oracle Field Service Mobility Cloud Service and the plug-in use the same global browser history object. If the plug-in accidentally corrupts the history object, then it will not be possible to return from the plug-in to Oracle Field Service Mobility Cloud Service using the Back button. Work carefully with the browser history in your plug-ins.

Example of "close" Method with Different "backScreen" Cases

// start_activity
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "start_activity",
    "backActivityId": "4225473"
}
   
// end_activity
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "end_activity",
    "backActivityId": "4225473"
}
   
// cancel_activity
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "cancel_activity",
    "backActivityId": "4225473"
}
   
// notdone_cancel
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "notdone_activity",
    "backActivityId": "4225473"
}
   
// suspend_activity
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "suspend_activity",
    "backActivityId": "4225473"
}
   
// delay_activity
{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "delay_activity",
    "backActivityId": "4225473"
}

Storing and Passing Sensitive Information

You can store and pass sensitive data such as login credentials in the plug-in.

You add this information in the Secure parameters section in the Add action link or Edit action link screens, when you configure a plug-in. The Secure parameters section includes the Parameter name and Parameter value fields. The data entered in these fields is encrypted and stored in the database. Changes to this data are sent to Oracle Field Service Mobility Cloud Service during the next synchronization. This data is sent to the plug-in when the next message is sent. The plug-in also receives the up-to-date data with every message.

When sensitive data is sent to the plug-in, the message contains the new field securedData. securedData is included only if at least one key-value pair is configured on the Add action link screen. The init, open, and wakeup methods support the securedData field.

Format of securedData: securedData field is an object, where:
  • Each key is a String, which equals to the contents of "key" text input on the Add action link or the Edit action link screen.

  • Each value is a String, which equals to the contents of "value" text input for the corresponding key on the Add action link or the Edit action link screen.

  • Order of entries may not be identical to the order of key-value pairs on the Add action link or the Edit action link screen.

Example of the 'open' method data for Supervisor plug-in: Consider the following configuration:
This figure shows the Secure parameters section with key value pairs configured in the Add action link screen.
The plug-in receives the following message upon opening:
{
    "apiVersion": 1,
    "method": "open",
    "entity": "activityList",
    "resource": {
        "external_id": "33001",
        "manager": "admin"
    },
    "activityList": {
        "4224031": {
            "aid": "4224031"
        }
    },
    "inventoryList": {
        "21064417": {
            "invid": "21064417"
        }
    },
    "securedData": {
        "ofscInstance": "company.test",
        "ofscRestEndpoint": "https://api.etadirect.com/rest/",
        "ofscRestClientId": "sample_app",
        "ofscRestClientSecret": "d1e0f03636747b968cd66ead50bd53984e1f1393a3e1503c4e4be9421be00aa5"
    }
}

Error Handling

When Oracle Field Service Cloud receives a message from a plug-in with the close method, it validates all entity properties and their values. It applies the updates only if no rules are violated. After updating, the plug-in is closed. Otherwise, the application sends a message with the error method containing the list of found errors.

Error method

The error message contains no entity collections, instead, it includes the 'errors' field containing the list of errors:
{
    "apiVersion": 1,
    "method": "error",
    "entity": "activityList",
    "errors": [
        {
            "type": "TYPE_ENTITY_PROPERTY",
            "code": "CODE_ACTIVITY_STATUS_INVALID",
            "entity": "activity",
            "entityId": "3956532",
            "propertyLabel": "astatus"
        },
        {
            "type": "TYPE_ENTITY_PROPERTY",
            "code": "CODE_MANDATORY_PROPERTY_EMPTY",
            "entity": "inventory",
            "entityId": "20998086",
            "propertyLabel": "inv_aid"
        }
    ]
}
Each element of the error list is an object always containing the following fields:
  • type: Describes the type of error which occurred during the message processing, for example, invalid property value, internal error, and so on. Type determines the additional fields available in the error object, for example, property label.

  • code: Contains a more detailed description of the error, for example, validation rule violated by the data sent by the plug-in.

Each element may optionally contain additional fields, such as entity, entityId, propertyLabel depending on the type of the error.
The following table describes the types of errors:

Type Occurs When… Available Message Fields
Error types related to entities
TYPE_ENTITY_ACTION The requested action is not applicable for the specified entity.
  • entity
  • entityId
TYPE_ENTITY_PROPERTY The value of one of the properties submitted by the plug-in to be updated is invalid.

or

It violates some business rule for the given entity as well as the conditions.

  • entity
  • entityId
  • propertyLabel
TYPE_INTERNAL Oracle Field Service Cloud is unable to process the message due to: Invalid format or contents of the message, or Unexpected internal error
Error types related to action
TYPE_ACTION_ERROR Action have an invalid format or in inapplicable
  • actionId

  • entity

  • entityId

TYPE_ACTION_PARAM Action param has an invalid value or mandatory param is missing
  • actionId

  • entity

  • entityId

  • paramName

TYPE_ACTION_PROPERTY Value of one of the properties, submitted by the plug-in to be updated in the "properties" param, has invalid value
  • actionId

  • entity

  • entityId

  • propertyLabel

TYPE_ACTION_FAILED Action is rejected due to incorrect value of action params, which can't be checked at the validation stage
  • actionId

  • entity

  • entityId

Available message fields:
  • entity: The entity whose data is invalid (activity or inventory).

  • entityId: The ID of the entity whose data is invalid (equals aid for activity and invid for inventory, for example, 10028719).

  • actionId: The zero-based order number of erroneous action in the actions list, sent by plugin. E.g. 0, 1, 17 etc.

  • propertyLabel: The label of the property, the value of which is invalid, for example, customer_number, WO_TYPE.

Error Codes for Entities

The following table describes the error codes for entities:

Code Occurs When...
TYPE_ENTITY_ACTION
CODE_ACTION_ON_PAST_DATE_NOT_ALLOWED The requested action is forbidden for the entity if it is assigned for an archived (past) route:
  • Updating properties of activity which is in the past and overnight/overtime limit has elapsed
  • Updating properties of inventory in the customer, installed, or deinstalled pool of the activity which is in the past and overnight or overtime limit has elapsed
TYPE_ENTITY_PROPERTY
CODE_PROPERTY_VALUE_TOO_LARGE Any of the following:
  • Property type is field and the length of its value exceeds 119 UTF-16 code points
  • Property type is file, its GUI type is signature, and the length of its value exceeds 102400 UTF-16 code points
  • Property is neither field nor signature and the length of its value exceeds 32767UTF-16 code points
CODE_MANDATORY_PROPERTY_EMPTY Any of the following:

For activity: astatus value is empty

For inventory:

  • invpool is install, deinstall or customer and inv_aid value is empty
  • invpool is install, deinstall or provider and inv_pid value is empty
  • invpool value is empty
CODE_ACTIVITY_STATUS_INVALID Any of the following:
  • astatus of activity is not equal to any of the following: pending, started, complete, suspended, notdone, cancelled
  • Transition from the current activity status to the new one specified in astatus is not allowed.
CODE_INVENTORY_POOL_INVALID Any of the following:
  • invpool of inventory is not equal to any of the following: customer, install, deinstall, provider
  • Transition from the current inventory pool to the new one specified in invpool is not allowed.
CODE_INVENTORY_AID_INVALID Any of the following:
  • invpool of inventory is provider and inv_aid value is not empty
  • invpool of inventory is customer or deinstall and the submitted inv_aid value is not equal to the current value of inv_aid
  • inv_aid is not equal to aid of the started activity in the same route and the submitted inv_aid value is not equal to the current value of inv_aid
CODE_INVENTORY_PID_INVALID Any of the following:
  • invpool of inventory is customer and inv_pid value is not empty
  • invpool of inventory is deinstall and inv_pid value is not equal to the current value of inv_pid and is not equal to pid of the selected resource or their teammates
  • invpool of inventory is provider, install or deinstall and the submitted inv_pid value is not equal to the current value of inv_pid
CODE_ACTIVITY_STATUS_INVALID_FOR_FUTURE astatus is not pending or cancelled and activity is assigned for the day in future relative to the current date in the resources time zone
CODE_ACTIVITY_STATUS_STARTED_ALREADY_IN_QUEUE astatus is started and there is another started activity in the same route
CODE_ACTIVITY_STATUS_INVALID_FOR_INACTIVE_QUEUE astatus is not pending or cancelled and activity is assigned to a not activated or deactivated route
TYPE_INTERNAL
CODE_UNKNOWN Oracle Field Service Cloud is unable to process message due to: Invalid format or content of the message or Unexpected Oracle Field Service Cloud internal error occurred

Error Codes for Actions

The following table describes the error codes for actions:

Code Caused by Action Cause
TYPE_ACTION_ERROR
CODE_ACTION_ON_PAST_DATE_NOT_ALLOWED
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

  • delete

Any of these:
  • "inv_aid" param of "install", "deisntall", "undo_install" or "undo_deinstall" action is equal to id of activity that is assigned for past date

  • "inv_aid" param of "create" or "delete" action is equal to id of activity that is assigned for past date, and "invpool" is "customer", "install" or "deinstall"

CODE_ENTITY_ID_INVALID
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

  • delete

"invid" param is not equal to id of any inventory in available pools
CODE_ACTION_UNKNOWN "action" param is not equal to one of the supported inventory actions (e.g. "install", "create")
CODE_ACTION_ENTITY_UNKNOWN "entity" param is not equal to "inventory"
TYPE_ACTION_PARAM
CODE_ACTION_INVENTORY_AID_INVALID create "inv_aid" param is sent for "create" action, and "invpool" is "provider"
CODE_ACTION_INVENTORY_PID_INVALID
  • deinstall

  • create

Any of these:
  • "inv_pid" param value is not equal to id of current resource or his teammates

  • "inv_pid" param is sent for "create" action, and "invpool" is "customer"

CODE_ACTION_INVENTORY_POOL_INVALID create "invpool" param value is not equal to one of: "customer", "install", "deinstall", "provider"
CODE_ACTION_INVENTORY_TYPE_INVALID create "invtype" param value is not equal to label of one of Inventory Types, configured for Oracle Field Service Cloud
CODE_ACTION_MANDATORY_PARAM_EMPTY
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

  • delete

Any of these:
  • "invid" param is not sent or its value is empty for "install", "deinstall", "undo_install", "undo_deinstall" or "delete" action

  • "invpool" param of "create" action is not sent or is empty

  • "inv_aid" param of "install" action is not sent or is empty

  • "inv_pid" param of "deinstall" action is not sent or is empty

  • "inv_aid" param of "create" action is not sent or is empty, and "invpool" is "customer", "install" or "deinstall"

  • "inv_pid" param of "create" action is not sent or is empty, and "invpool" is "provider", "install" or "deinstall"

  • "quantity" is not sent or is empty for inventory of non-serialized type

CODE_ACTION_PARAM_VALUE_INVALID
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

Any of these:
  • "properties" param value is sent but is not a plain object

  • "quantity" is sent for inventory of serialized type

  • "quantity" is not a positive integer number

TYPE_ACTION_PROPERTY
CODE_ACTION_MANDATORY_PROPERTY_EMPTY
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

[Reserved]
CODE_ACTION_PROPERTY_VALUE_INVALID
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

Any of these:
  • Property type is 'file', its GUI type is 'signature' and its value is not a valid Data URI or it has the invalid MIME-type

  • Property type is 'enumeration', and its value is not a valid enumeration item's index

CODE_ACTION_PROPERTY_VALUE_TOO_LARGE
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

Any of these:
  • Property type is 'field' and length of its value exceeds 119 UTF-16 codepoints

  • Property type is 'file', its GUI type is 'signature' and length of its value exceeds 102400 UTF-16 codepoints

  • Property is neither field nor signature and length of its value exceeds 32767 UTF-16 codepoints

TYPE_ACTION_FAILED
CODE_ACTION_INVENTORY_ACTIVITY_STATUS_INVALID
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

  • delete

Any of these:
  • "inv_aid" param of "install", "deinstall", "undo_install" or "undo_deinstall" action is not equal to id of started activity

  • "inv_aid" param of "create" or "delete" action is not equal to id of started activity, and "invpool" is "install" or "deinstall"

  • "inv_aid" param of "create" or "delete" action is equal to id of completed, not done or cancelled activity, and "invpool" is "customer"

  • "invid" param of "deisntall", "undo_install" or "undo_deinstall" action is equal to id of inventory, associated with not started regular activity

  • "invid" param of "deisntall", "undo_install" or "undo_deinstall" action is equal to id of inventory, associated with multi-day activity, that is not a master activity of current started segment

CODE_ACTION_INVENTORY_ACTIVITY_TYPE_INVALID
  • install

  • create

"inv_aid" param equal to id of activity, whose type doesn't support inventories
CODE_ACTION_INVENTORY_ACTIVITY_UNKNOWN
  • install

  • create

"inv_aid" param isn't equal to:
  • id of one of activities in the queue of the current provider / the teammates

  • id of one of activities in the unscheduled pool

CODE_ACTION_INVENTORY_POOL_TRANSITION_INVALID
  • install

  • deinstall

Any of these:
  • "invid" param of "install" action is equal to id of inventory, whose "invpool" isn't equal to "provider"

  • "invid" param of "deinstall" action is equal to id of inventory, whose "invpool" isn't equal to "customer"

  • "invid" param of "undo_install" action is equal to id of inventory, whose "invpool" isn't equal to "install"

  • "invid" param of "undo_deinstall" action is equal to id of inventory, whose "invpool" isn't equal to "deinstall"

TYPE_INTERNAL
CODE_UNKNOWN
  • install

  • deinstall

  • undo_install

  • undo_deinstall

  • create

Oracle Field Service Cloud is unable to process the message due to unexpected change of the system's state

Notifying When Offline or Online

The following figure describes the flow of steps when Oracle Field Service Mobility Cloud Service switches online and the application retries to connect to the Internet:
This figure describes the flow of steps when switching online.
The steps that are executed when the application switches online are:
  • Oracle Field Service Mobility Cloud Service switches to online mode.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Wakeup method is executed; here, the event is ‘online’.

  • The Sleep method is executed; here, the wakeupNeeded parameter is set to ‘true’.

  • The iframe is destroyed, if it is created.

The steps that are executed when the application retries to connect to the Internet are:
  • Oracle Field Service Mobility Cloud Service waits for five minutes.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Wakeup method is executed; here, the event is ‘online’.

  • The Sleep method is executed; here, the wakeupNeeded parameter is set to ‘false’.

  • The iframe is destroyed, if it is created.

The following figure shows the flow of steps when the plug-in is unresponsive to the application’s requests:
This figure describes the flow of steps when the plug-in doesn’t respond to the application’s requests.
The flow of steps when the plug-in doesn’t respond to the application’s requests at the time of switching online is:
  • Oracle Field Service Mobility Cloud Service switches to online mode.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Wakeup method is executed; here, the event is ‘online’.

  • Oracle Field Service Mobility Cloud Service waits for two minutes.

  • The iframe is destroyed, if it is created.

The following figure shows the flow of steps when the plug-in is opened by a user after the application switches to online mode:
This figure describes the flow of steps when the plug-in is opened by a user.
The flow of steps when the plug-in is opened by a user after the application switches to online mode is:
  • Oracle Field Service Mobility Cloud Service detects the active connection to the Internet.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Wakeup method is executed.

  • The user clicks the action link.

  • The iframe is destroyed, if it is created.

  • The iframe is created, if required.

  • The Ready method is executed.

  • The Open method is executed.

  • The Close method is executed.

  • The iframe is destroyed, if it is created.

The plug-in's iframe window is killed after the Close message is processed, regardless of whether the device is online or offline. So, no code runs after the plug-in is closed. It may have data that must be synchronized with its server, OFSC REST API, or with third-party services. So, the plug-in sends a message to Mobility when the data is synchronized and Mobility sends a message to the plug-in when it is online. If the plug-in supports offline mode, request Mobility to invoke it when the network connectivity is established.

A new parameter "wakeupNeeded" is added to the "close" message to perform the synchronization. If it's set to true, the hidden plug-in's iframe is opened in the background, as soon as Mobility goes online, but not earlier than 5 minutes (300 s) after the plug-in is closed. See updated JSON Schema of the "close" message. After the plug-in's iframe is opened, Mobility sends the "wakeup" message to the plug-in in response to the "ready" message.

The plug-in must send the "sleep" message back to Mobility when it finishes synchronization, to allow the application to destroy the iframe. If the plug-in tried to synchronize, but couldn't sent all the data, it must send the "sleep" message with the "wakeupNeeded" param set to true. In this case, Mobility opens the plug-in's iframe in the background again, as soon as Mobility goes online, but no earlier than 5 minutes after the plug-in is closed. If the plug-in doesn't send the "sleep" message in two minutes (120 s) after the "wakeup" message is sent, Mobility destroys its iframe and reopens it, as if the plug-in sent the "sleep" message with the "wakeupNeeded" param set to true.

To allow the plug-in to synchronize even after refreshing Mobility's page or closing the browser, the new parameter "wakeupNeeded" is added to the "initEnd" message. If the plug-in didn't synchronize during the two minutes that is allowed for initialization, it must send the "initEnd" message with the "wakeupNeeded" param set to true. In this case, Mobility opens the plug-in's iframe in the background, as soon as Mobility goes online, but no earlier than 5 minutes after "initEnd" receiving the message.

The plug-in is opened in 5 minutes after it's closed, if the "wakeupNeeded" param of "close", "sleep" or "initEnd" messages are set to true, even if Mobility didn't detect offline when the plug-in was opened or closed. If the user opens the plug-in by clicking its action link in Mobility, the background iframe is destroyed without sending any messages to it. If plug-in still has data to be synchronized, it must send the "close" message with the "wakeupNeeded" param set to true.

Property Value Length Limits

Limits are applied to the property values that are submitted by the plug-in through the plug-in API. If the length of a value exceeds the limit, an error is returned as part of the message, using the error method.

Fields (property type is field): Fields are encrypted by AES and stored in the TINYBLOB columns. AES output block is 16 bytes, so the ciphertext length is always divisible by 16 (L % 16 = 0). Additionally, AES requires one extra block for the data whose length is divisible by 16. So, the maximum plain data to store is ceil(255/16)*16 - 1 = 239. JavaScript uses UTF-16 for strings, so one Unicode character may take up 2 to 4 bytes. But the String.length property uses UTF-16 code points for counting, which is 2 bytes. Therefore, the length of the string containing one 4-byte UTF-16 char will be 2. So, only ceil(239/2) = 119 code points can be stored without truncating.

Signatures (property type is file and GUI element is Signature): We assume that the value contains only MIME-type and correct base64 string, so each character takes up 2 bytes as JavaScript uses UTF-16. To avoid overflow of the LocalStorage we limit each signature to 200 KB (1024*200/2 = 102400 characters).

Properties (any other property type): Properties are stored in TEXT columns. The maximum amount of data to store is 65 535 bytes (2^16 - 1). JavaScript uses UTF-16 for strings, so one character may take up 2 to 4 bytes. But the String.length property uses UTF-16 code points for counting, which is 2 bytes. Therefore, length of the string containing one 4-byte UTF-16 char will be 2. So, in the worst case scenario, only ceil(65535/2) = 32767 code points can be stored without truncating.

JSON Schema for Message Data

ready Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["ready"]
        },
        "sendInitData": {
            "type": "boolean"
        },
        "showHeader": {
            "type": "boolean"
        },
        "enableBackButton": {
            "type": "boolean"
        },
        "dataItems": {
            "type": "array",
            "items": {
                "type": "string",
                "enum": [
                    "resource",
                    "scheduledActivites",
                    "nonScheduledActivites",
                    "resourceInventories",
                    "installedInventories",
                    "deinstalledInventories",
                    "customerInventories"
                ]
            }
        }
    },
    "required": ["apiVersion", "method"]
 }

init Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["init"]
        }
    },
    "required": ["apiVersion", "method"]
 }

initEnd Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["initEnd"]
        },
        "wakeupNeeded": {
            "type": "boolean"
        }
    },
    "required": ["apiVersion", "method"]
 }

open Method

{
    "apiVersion": {"type": "number", "enum": ["1"]},
    "method": {"type": "string", "enum": ["open"]},
    "entity": {
        "type": "string",
        "enum": ["activity", "activitiyList", "activityInventory", "activityInventoryList", "inventory", "inventoryList"]
    },
    "resource": {
        "type": "object",
        "properties": {
            "pid": {"type": "number"},
            "pname": {"type": "string"},
            "external_id": {"type": "string"},
            "ptype": {"type": "string"},
            "email": {"type": "string"},
            "pphone": {"type": "string"},
            "pcapacity_bucket": {"type": "number"}
        },
        "patternProperties": {
            "^.+$": {
                "anyOf": [
                    {"type": "string"},
                    {"type": "number"}
                ],
                "description": "Key: Any property of an OFSC Activity; Value: value of this property"
            }
        }
    },
    "activity": {
        "type": "object",
        "properties": {
            "cname": {"type": "string"},
            "caddress": {"type": "string"},
            "ccity": {"type": "string"},
            "czip": {"type": "number"},
            "cstate": {"type": "string"},
            "customer_number": {"type": "string"},
            "c_zid": {"type": "number"},
            "cphone": {"type": "string"},
            "cemail": {"type": "string"},
            "ccell": {"type": "string"},
            "atype": {"type": "string"},
            "aworktype": {"type": "string"},
            "time_slot": {"type": "number"},
            "service_window": {"type": "string"},
            "appt_number": {"type": "string"},
            "clanguage": {"type": "number"},
            "cmessagetime": {"type": "number"},
            "activity_workskills": {"type": "string"},
            "length": {"type": "number"},
            "ETA": {"type": "string"},
            "astatus": {"type": "string"},
            "aid": {"type": "number"},
            "aworkzone": {"type": "number"},
            "end_time": {"type": "string"},
            "delivery_window": {"type": "string"},
            "acoord_status": {"type": "string"},
            "acoord_x": {"type": "number"},
            "acoord_y": {"type": "number"},
            "travel": {"type": "number"},
            "sla_window_start": {"type": "string"},
            "sla_window_end": {"type": "string"},
            "apoints": {"type": "number"},
            "activity_capacity_categories": {"type": "string"},
            "atime_of_booking": {"type": "string"},
            "atime_of_assignment": {"type": "string"},
            "auto_routed_to_provider_id": {"type": "number"},
            "auto_routed_to_date": {"type": "string"},
            "auto_routed_to_provider_name": {"type": "string"},
            "first_manual_operation": {"type": "number"},
            "first_manual_operation_interface": {"type": "number"},
            "first_manual_operation_user_id": {"type": "number"},
            "first_manual_operation_user_login": {"type": "string"},
            "first_manual_operation_user_name": {"type": "string"}
        },
        "patternProperties": {
            "^.+$": {
                "anyOf": [
                    {"type": "string"},
                    {"type": "number"}
                ],
                "description": "Key: Any property of an OFSC Activity; Value: value of this property"
            }
        }
    },
    "inventory": {
        "type": "object",
        "properties": {
            "invid": {"type": "number"},
            "inv_aid": {"type": "number"},
            "inv_pid": {"type": "number"},
            "invpool": {"type": "string"},
            "invsn": {"type": "string"},
            "invtype": {"type": "string"},
            "quantity": {"type": "number"},
            "inv_change_invid": {"type": "number"}
        },
        "patternProperties": {
            "^.+$": {
                "anyOf": [
                    {"type": "string"},
                    {"type": "number"}
                ],
                "description": "Key: Any property of an OFSC Activity; Value: value of this property"
            }
        }
    },
    "activityList": {
        "type": "object",
        "patternProperties": {
            "^//d+$": {
                "type": "object",
                "properties": {
                    "cname": {"type": "string"},
                    "caddress": {"type": "string"},
                    "ccity": {"type": "string"},
                    "czip": {"type": "number"},
                    "cstate": {"type": "string"},
                    "customer_number": {"type": "string"},
                    "c_zid": {"type": "number"},
                    "cphone": {"type": "string"},
                    "cemail": {"type": "string"},
                    "ccell": {"type": "string"},
                    "atype": {"type": "string"},
                    "aworktype": {"type": "string"},
                    "time_slot": {"type": "number"},
                    "service_window": {"type": "string"},
                    "appt_number": {"type": "string"},
                    "clanguage": {"type": "number"},
                    "cmessagetime": {"type": "number"},
                    "activity_workskills": {"type": "string"},
                    "length": {"type": "number"},
                    "ETA": {"type": "string"},
                    "astatus": {"type": "string"},
                    "aid": {"type": "number"},
                    "aworkzone": {"type": "number"},
                    "end_time": {"type": "string"},
                    "delivery_window": {"type": "string"},
                    "acoord_status": {"type": "string"},
                    "acoord_x": {"type": "number"},
                    "acoord_y": {"type": "number"},
                    "travel": {"type": "number"},
                    "sla_window_start": {"type": "string"},
                    "sla_window_end": {"type": "string"},
                    "apoints": {"type": "number"},
                    "activity_capacity_categories": {"type": "string"},
                    "atime_of_booking": {"type": "string"},
                    "atime_of_assignment": {"type": "string"},
                    "auto_routed_to_provider_id": {"type": "number"},
                    "auto_routed_to_date": {"type": "string"},
                    "auto_routed_to_provider_name": {"type": "string"},
                    "first_manual_operation": {"type": "number"},
                    "first_manual_operation_interface": {"type": "number"},
                    "first_manual_operation_user_id": {"type": "number"},
                    "first_manual_operation_user_login": {"type": "string"},
                    "first_manual_operation_user_name": {"type": "string"}
                },
                "patternProperties": {
                    "^.+$": {
                        "anyOf": [
                            {"type": "string"},
                            {"type": "number"}
                        ],
                        "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                    }
                }
            }
        }
    },
    "inventoryList": {
        "type": "object",
        "patternProperties": {
            "^//d+$": {
                "type": "object",
                "properties": {
                    "invid": {"type": "number"},
                    "inv_aid": {"type": "number"},
                    "inv_pid": {"type": "number"},
                    "invpool": {"type": "string"},
                    "invsn": {"type": "string"},
                    "invtype": {"type": "string"},
                    "quantity": {"type": "number"},
                    "inv_change_invid": {"type": "number"}
                },
                "patternProperties": {
                    "^.+$": {
                        "anyOf": [
                            {"type": "string"},
                            {"type": "number"}
                        ],
                        "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                    }
                }
            }
        }
    },
    "required": ["apiVersion", "method", "entity", "resource"]
}
Note: position_in_route, time_delivered, date, pid, atravelarea, activity_alerts, activity_compliance, eta_end_time fields are not supported and may not be added to the Activity properties for Mobility context layout.

close Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["close"]
        },
        "backScreen": {
            "type": "string",
            "enum": ["default", "activity_by_id", "next_activity", "activity_list", "start_activity", "end_activity",
                    "cancel_activity", "notdone_activity", "suspend_activity", "delay_activity"]
        },
        "backActivityId": {
            "type": "string"
        },
        "wakupNeeded": {
            "type": "boolean"
        },
        "activity": {
            "type": "object",
            "required": ["aid"],
            "properties": {
                "cname": {
                    "type": "string"
                },
                "caddress": {
                    "type": "string"
                },
                "ccity": {
                    "type": "string"
                },
                "czip": {
                    "type": "number"
                },
                "cstate": {
                    "type": "string"
                },
                "customer_number": {
                    "type": "string"
                },
                "c_zid": {
                    "type": "number"
                },
                "cphone": {
                    "type": "string"
                },
                "cemail": {
                    "type": "string"
                },
                "ccell": {
                    "type": "string"
                },
                "time_slot": {
                    "type": "number"
                },
                "service_window": {
                    "type": "string"
                },
                "appt_number": {
                    "type": "string"
                },
                "clanguage": {
                    "type": "number"
                },
                "cmessagetime": {
                    "type": "number"
                },
                "length": {
                    "type": "number"
                },
                "astatus": {
                    "type": "string"
                },
                "aid": {
                    "type": "string"
                },
                "sla_window_start": {
                    "type": "string"
                },
                "sla_window_end": {
                    "type": "string"
                },
                "apoints": {
                    "type": "number"
                }
            },
            "patternProperties": {
                "^.+$": {
                    "anyOf": [
                        { "type": "string" },
                        { "type": "number" },
                        {
                            "type": "object",
                            "properties": {
                                "fileName" : {
                                    "type": "string"
                                },
                                "fileContents" : {
                                     "type": "object"
                                }
                            },
                            "required": ["fileName", "fileContents"]
                        }
                    ],
                    "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                }
            }
        },
        "inventory": {
            "type": "object",
            "required": ["invid"],
            "properties": {
                "invid": {
                    "type": "string"
                },
                "inv_aid": {
                    "type": "string"
                },
                "inv_pid": {
                    "type": "string"
                },
                "invpool": {
                    "type": "string"
                },
                "invsn": {
                    "type": "string"
                },
                "invtype": {
                    "type": "string"
                },
                "quantity": {
                    "type": "number"
                }
            },
            "patternProperties": {
                "^.+$": {
                    "anyOf": [
                        { "type": "string" },
                        { "type": "number" },
                        {
                            "type": "object",
                            "properties": {
                                "fileName" : {
                                    "type": "string"
                                },
                                "fileContents" : {
                                     "type": "object"
                                }
                            },
                            "required": ["fileName", "fileContents"]
                        }
                    ],
                    "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                }
            }
        },
        "activityList": {
            "type": "object",
            "patternProperties": {
                "^\\d+$": {
                    "type": "object",
                    "properties": {
                        "cname": {
                            "type": "string"
                        },
                        "caddress": {
                            "type": "string"
                        },
                        "ccity": {
                            "type": "string"
                        },
                        "czip": {
                            "type": "number"
                        },
                        "cstate": {
                            "type": "string"
                        },
                        "customer_number": {
                            "type": "string"
                        },
                        "c_zid": {
                            "type": "number"
                        },
                        "cphone": {
                            "type": "string"
                        },
                        "cemail": {
                            "type": "string"
                        },
                        "ccell": {
                            "type": "string"
                        },
                        "time_slot": {
                            "type": "number"
                        },
                        "service_window": {
                            "type": "string"
                        },
                        "appt_number": {
                            "type": "string"
                        },
                        "clanguage": {
                            "type": "number"
                        },
                        "cmessagetime": {
                            "type": "number"
                        },
                        "length": {
                            "type": "number"
                        },
                        "astatus": {
                            "type": "string"
                        },
                        "aid": {
                            "type": "string"
                        },
                        "sla_window_start": {
                            "type": "string"
                        },
                        "sla_window_end": {
                            "type": "string"
                        },
                        "apoints": {
                            "type": "number"
                        }
                    },
                    "patternProperties": {
                        "^.+$": {
                            "anyOf": [
                                { "type": "string" },
                                { "type": "number" },
                                {
                                    "type": "object",
                                    "properties": {
                                        "fileName" : {
                                            "type": "string"
                                        },
                                        "fileContents" : {
                                             "type": "object"
                                        }
                                    },
                                    "required": ["fileName", "fileContents"]
                                }
                            ],
                            "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                        }
                    },
                    "required": ["aid"]
                }
            },
            "inventoryList": {
                "type": "object",
                "patternProperties": {
                    "^\\d+$": {
                        "type": "object",
                        "required": false,
                        "properties": {
                            "invid": {
                                "type": "string"
                            },
                            "inv_aid": {
                                "type": "string"
                            },
                            "inv_pid": {
                                "type": "string"
                            },
                            "invpool": {
                                "type": "string"
                            },
                            "invsn": {
                                "type": "string"
                            },
                            "invtype": {
                                "type": "string"
                            },
                            "quantity": {
                                "type": "number"
                            }
                        },
                        "patternProperties": {
                            "^.+$": {
                                "anyOf": [
                                    { "type": "string" },
                                    { "type": "number" },
                                    {
                                        "type": "object",
                                        "properties": {
                                            "fileName" : {
                                                "type": "string"
                                            },
                                            "fileContents" : {
                                                 "type": "object"
                                            }
                                        },
                                        "required": ["fileName", "fileContents"]
                                    }
                                ],
                                "description": "Key: Any property of an OFSC Activity; Value: value of this property"
                            }
                        }
                    }
                }
            },
            "actions": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "entity": {
                            "type": "string"
                        },
                        "action": {
                            "type": "string"
                        },
                        "invtype": {
                            "type": "string"
                        },
                        "invpool": {
                            "type": "string"
                        },
                        "invid": {
                            "type": "string"
                        },
                        "inv_aid": {
                            "type": "string"
                        },
                        "inv_pid": {
                            "type": "string"
                        },
                        "quantity": {
                            "type": "number"
                        },
                        "properties": {
                            "type": "object",
                            "patternProperties": {
                                "^.+$": {
                                    "anyOf": [
                                        { "type": "string" },
                                        { "type": "number" },
                                        {
                                            "type": "object",
                                            "properties": {
                                                "fileName" : {
                                                    "type": "string"
                                                },
                                                "fileContents" : {
                                                    "type": "object"
                                                }
                                            },
                                            "required": ["fileName", "fileContents"]
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "required": [
                        "entity", "action"
                    ]
                }
            }
        }
    },
    "required": ["apiVersion", "method"]
} 

wakeup Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["wakup"]
        },
        "event": {
            "type": "string",
            "enum": ["online"]
        }
    },
    "required": ["apiVersion", "method"]
 }

sleep Method

{
    "type": "object",
    "properties": {
        "apiVersion": {
            "type": "number",
            "enum": [1]
        },
        "method": {
            "type": "string",
            "enum": ["sleep"]
        },
        "wakeupNeeded": {
            "type": "boolean"
        }
    },
    "required": ["apiVersion", "method"]
 }

error Method

{
    "apiVersion": {"type": "number", "enum": ["1"]},
    "method": {"type": "string", "enum": ["error"]},
    "entity": {
        "type": "string",
        "enum": ["activity", "activitiyList", "activityInventory", "activityInventoryList", "inventory", "inventoryList"]
    },
    "errors": {
        "type": "object",
        "fields": {
            "type": {"type": "string", "enum": ["TYPE_ENTITY_ACTION", "TYPE_ENTITY_PROPERTY", "TYPE_INTERNAL"]},
            "code": {
                "type": "string",
                "enum": [
                    "CODE_ACTION_ON_PAST_DATE_NOT_ALLOWED", 
                    "CODE_PROPERTY_VALUE_TOO_LARGE", 
                    "CODE_MANDATORY_PROPERTY_EMPTY", 
                    "CODE_ACTIVITY_STATUS_INVALID", 
                    "CODE_INVENTORY_POOL_INVALID", 
                    "CODE_INVENTORY_AID_INVALID", 
                    "CODE_INVENTORY_PID_INVALID", 
                    "CODE_ACTIVITY_STATUS_INVALID_FOR_FUTURE", 
                    "CODE_ACTIVITY_STATUS_STARTED_ALREADY_IN_QUEUE", 
                    "CODE_ACTIVITY_STATUS_INVALID_FOR_INACTIVE_QUEUE", 
                    "CODE_UNKNOWN"
                ]
            },
            "entity": {"type": "string", "enum": ["activity", "inventory"]},
            "entityId": {"type": "string"},
            "propertyLabel": {"type": "string"}
        },
        "required": ["type", "code"]
    },
    "required": ["apiVersion", "method"]
}

JSON Example

open Method

{
    "apiVersion": 1,
    "method": "open",
    "entity": "activity",
    "resource": {
        "pid": 5000038,
        "pname": "RAYNER, Faye",
        "external_id": "55038",
        "gender": "1"
    },
    "activity": {
        "WO_COMMENTS": "AUTOMATIC TRANSFER WORK ORDER/n/n",
        "astatus": "started",
        "aid": 3956534
    },
    "inventories": {
        "20997919": {
            "invid": 20997919,
            "inv_aid": 3956534,
            "inv_pid": 5000038,
            "invpool": "install",
            "invsn": "SABDFWKNZ"
        },
        "20998078": {
            "invid": 20998078,
            "inv_aid": 3956532,
            "invpool": "customer",
            "invsn": "5CTBME4AW090379"
        },
        "20998080": {
            "invid": 20998080,
            "inv_aid": 3956533,
            "invpool": "customer",
            "invsn": "SABGZTWGM"
        }
    }
}

close Method

{
    "apiVersion": 1,
    "method": "close",
    "backScreen": "default",
    "actions":
    [
        // INSTALL
        {
            "entity": "inventory",
            "action": "install",
            "invid": 21258426,
            "inv_aid": 4224031,
            "properties": // Properties can be updated too
            {
                "PORT_INFO": "A0|1|1|0|7.9|QF9-0719537",
                "EQUIPMENT_ETHERNET": "08:00:27:ea:d1:bd",
            }
        },
        {
            "entity": "inventory",
            "action": "install",
            "invid": 21229417,
            "inv_aid": 4224031,
            "quantity": 12, // Install only 12 pieces of NSI
  
            "properties": // Model should be set if needed
            {
                "inventory_model": "RG6 - BLK",
            }
        },
  
        // DEINSTALL
        {
            "entity": "inventory",
            "action": "deinstall",
            "invid": 21064418,
            "inv_pid": 3000001
        },
  
        // CREATE
        {
            "entity": "inventory",
            "action": "create",
            "invtype": "NT",
            "invpool": "installed",
            "inv_aid": 4224031,
            "inv_pid": 3000001,
            "quantity": 100,
  
            "properties":
            {
                "inventory_model": "RG6 - BLK",
            }
        },
   
        // DELETE
        {
            "entity": "inventory",
            "action": "delete",
            "invid": "1484311067004-9891"
        }
    ]
}

Barcode Scanner Method

The plug-in framework supports remote procedure calls from Oracle Field Service Mobility Cloud Service Barcode Scanner Service. You can use this method and create a plug-in to scan barcodes. The Barcode Scanner button is available in the Inventory search screen, if you open Mobility through the native application. If you open the inventory list through a browser, the button is not available. The plug-in framework in release 18A is backward compatible with the version introduced in release 17.8.

If you use this method to create a relevant plug-in, your Android device turns into a scanner, so you need not use external tools such as custom Android keyboards. You can use the barcode Plug-in API to:

  • Find inventory in the pools and show where the inventory is currently.

  • Search an activity related to a specific inventory, in other words, scan inventory to search activities related to this inventory.

  • Show details of the inventory searched (Name, Label, etc.).

  • Depending on the pool where the inventory is available, suggest actions such as install, undo deinstall, undo exchange to the technician.

  • Allow entering and updating a barcode number through a keyboard.

Syntax

scanBarcode

Parts and equipment usually have barcodes printed on their package or on the device. This procedure provides barcode and 2D (for example, QR, DATAMATRIX) code scanner functionality to make the search easier for the required items in the inventory pools. When this procedure is called, the scanner window is opened, which shows the live camera picture. When the barcode is recognized, the scanner windows are closed, and the resulting values are sent to the plug-in through the callProcedureResult method. If the barcode scanner is unavailable or Oracle Field Service Mobility Cloud Service is not run inside the Mobile app, the corresponding error code is returned to the plug-in through an error message. Having Oracle Field Service Cloud Mobile (for Android or iOS) is a prerequisite to use the Barcode Scanner Mobile Plug-in Framework to search by barcode.

Supported barcode and 2D code types

Barcode Type Andriod iOS
QR_CODE Yes Yes
DATA_MATRIX Yes Yes
UPC_A Yes Yes
UPC_E Yes Yes
EAN_8 Yes Yes
EAN_13 Yes Yes
CODE_39 Yes Yes
CODE_93 Yes No
CODE_128 Yes Yes
CODABAR Yes No
ITF Yes Yes
RSS14 Yes No
RSS_EXPANDED Yes No

openLink

This procedure provides a common way to open external URLs either with Oracle Field Service Mobility Cloud Service run in the web browser or in Mobile app. When Oracle Field Service Cloud Mobile is used, the URL opens externally in a web browser. If not, it opens as a new browser tab.

callProcedure
{
	"apiVersion":1,
	"method":"callProcedure",
	"procedure":"scanBarcode",
	"callid":"123abc"
}
{
    "apiVersion": 1,
    "method": "callProcedure",
    "procedure": "openLink",
    "callId": "123abc",
    "params": {
       "url": "https://play.google.com/store/apps/details?id=com.oracle.ofsc"
    }
}
callProcedure Method Parameters:

Param Name Mandatory Type Description
apiVersion Yes Integer API version
method Yes String Must equal "callProcedure"
procedure Yes String Procedure name
callId Yes String Unique string identifier which is used to apply procedure response within plug-in
The current version of the method supports the scanBarcode and openLink values for the procedure parameter.
Example of callID generation
function generateCallId() {
    return btoa(String.fromCharCode.apply(null, window.crypto.getRandomValues(new Uint8Array(16))));
}
callProcedureResult method
Oracle Field Service Mobility Cloud Service sends the message with this method to the plug-in after the execution of a procedure initiated by the callProcedure method. If the procedure fails, the error message is sent instead. callProcedure method parameters:

Param Name Mandatory Type Description
apiVersion Yes Integer API version
method Yes String Must equal "callProcedureResult"
procedure Yes String Procedure name
resultData No String Result of procedure execution
scanBarcode procedure: For this procedure, the resultData param of callProcedureResult message is an object, which contains the following fields:

Key Type Description
apiVersion String API version
Format String Type of recognized barcode. See Supported barcode and 2D code types.
Cancelled String Equals true, if user closes the scanner window before the code is recognized.
When the method is successfully executed:
{
    	"apiVersion": 1,
    	"method": "callProcedureResult",
	"callid": "123abc"
	"resultData": {
        "text": "PT9012308",
        "format": "QR_CODE",
        "cancelled": false
    }
}
When the method is canceled:
{
    	"apiVersion": 1,
    	"method": "callProcedureResult",
	"callid": "123abc"
	"resultData": {
        "text": "PT9012308",
        "format": "QR_CODE",
        "cancelled": true
    }
}

Errors

Example
{
    code: "CODE_PROCEDURE_UNKNOWN",
    procedure: "scanBarcode"
}
Type of errors

Type Occurs When... Available Message Fields
TYPE_PROCEDURE_ERROR Procedure call not valid due to missed params, and procedure executed with error. Procedure [Name of the procedure where the error occurred.]
TYPE_PROCEDURE_PARAM Procedure params not valid or missed. Procedure [Name of the procedure where the error occurred.]
Error codes

Code Caused by Procedure Error Type Cause
TYPE_PROCEDURE_ERROR
CODE_CALL_ID_EMPTY scanBarcode Validation error Empty callId param.
CODE_CALL_ID_INVALID scanBarcode Validation error Invalid callId param.
CODE_CALL_ID_DUPLICATE scanBarcode Validation error Duplicate callId param.
CODE_PROCEDURE_FAILED - scanBarcode Execution error Procedure execution failed to various reasons.
CODE_PROCEDURE_UNKNOWN scanBarcode Execution error Procedure was called with unknown procedure name.
CODE_PROCEDURE_UNAVAILABLE scanBarcode Internal error Oracle Field Service Mobility Cloud Serviceservice related to procedure is not available.
CODE_PROCEDURE_ACCEPTS_NO_PARAMS scanBarcode Validation error Procedure was called with params.
TYPE_PROCEDURE_PARAM
CODE_PROCEDURE_MANDATORY_PARAM_EMPTY openLink Validation error Mandatory param is missed.
CODE_PROCEDURE_PARAM_VALUE_INVALID openLink Validation error Param value is not valid.

Querying the Parts Catalog

You can create a plug-in to query the parts catalog that is available in Oracle Field Service Cloud For more information on how to create or update the parts catalog through APIs, see the Integrating with Parts Catalog API guide.

The plug-in can perform the following functions:
  • Search for inventory

  • Get the structure of the catalog

  • Get items by label or ID

The plug-in framework includes the following procedures that run using the existing callProcedure method:
  • getPartsCatalogsStructure

  • getParts

  • searchParts

  • searchPartsContinue

getPartsCatalogsStructure

This procedure returns the result through the callProcedureResult method. The result includes the description, field and type schema for all available parts catalogs, as created using the create method of the Parts Catalog API.

Parameters: This method accepts no parameters.

Response: For each parts catalog, the procedure returns the following fields:

Field Type Parts Catalog API Parameter Description
catalogId Number
label String label
language String language
name name String Name of the catalog to be displayed in GUI
fieldSchemas Array field_schemas Array of fieldSchema items, each of which contains one of the fields to be set for the catalog
typeSchemas Array type_schemas Array of typeSchema items, each of which contains an item type and may also contain the inventory type corresponding to such item type
cacheLoadingState Object Status of loading the Parts Catalog contents to the device storage to be available in offline. Can be used to visualize the progress of loading.
fieldSchema item structure

Field Type Parts Catalog API Parameter Description
catalogId Number
label String label
language String language
name name String Name of the catalog to be displayed in GUI
fieldSchemas Array field_schemas Array of fieldSchema items, each of which contains one of the fields to be set for the catalog
typeSchemas Array type_schemas Array of typeSchema items, each of which contains an item type and may also contain the inventory type corresponding to such item type
cacheLoadingState Object Status of loading the Parts Catalog contents to the device storage to be available in offline. Can be used to visualize the progress of loading.
typeSchema item structure

Field Type Parts Catalog API Parameter Description
itemType String item_type Item type according to the catalog.
inventoryType String inventory_type Inventory type according to Oracle Field Service Cloud settings.
cacheLoadingState structure

Field Type Description
isLoaded String Whether all the needed data of the parts catalog is loaded and is available offline
loadedItemsNumber Number Number of catalog items that are loaded to the device
totalItemsNumber Number Total number of catalog items to be loaded to the device
loadedSize Number The amount of data that is loaded to a device (in bytes)
Example of a Request
{
    "apiVersion": 1,
    "callId": "CMFYN5AKpc9Yg1POv6773g==",
    "method": "callProcedure",
    "procedure": "getPartsCatalogsStructure"
}
Example of the Response
{
    "apiVersion": 1,
    "method": "callProcedureResult",
    "callId": "CMFYN5AKpc9Yg1POv6773g==",
    "resultData": [
        {
            "catalogId": 2,
            "label": "network",
            "language": "en",
            "name": "Network devices",
            "fieldSchemas": [
                {
                    "label": "model",
                    "name": "Model",
                    "propertyLabel": "switch_model",
                    "searchable": true,
                    "preview": true
                },
                {
                    "label": "ports",
                    "name": "Ports",
                    "propertyLabel": false,
                    "searchable": true,
                    "preview": false
                },
                {
                    "label": "price",
                    "name": "Price",
                    "propertyLabel": "switch_price",
                    "searchable": false,
                    "preview": false
                },
                {
                    "label": "vendor",
                    "name": "Vendor",
                    "propertyLabel": false,
                    "searchable": false,
                    "preview": true
                }
            ],
            "typeSchemas": [
                {
                    "itemType": "switch_type",
                    "inventoryType": "switch_general"
                },
                {
                    "itemType": "router_type",
                    "inventoryType": "router_general"
                }
            ],
            "cacheLoadingState": {
                "isLoaded": true,
                "loadedItemsNumber": 2,
                "loadedSize": 1138,
                "totalItemsNumber": 2
            }
        },
        {
            "catalogId": 4,
            "label": "misc",
            "language": "en",
            "name": "Miscellaneous parts",
            "fieldSchemas": [
                {
                    "label": "item_type",
                    "name": "Item Type",
                    "propertyLabel": false,
                    "searchable": false,
                    "preview": false
                },
                {
                    "label": "description",
                    "name": "Item description",
                    "propertyLabel": false,
                    "searchable": true,
                    "preview": true
                },
            ],
            "typeSchemas": [
                {
                    "itemType": "parts",
                    "inventoryType": "PART"
                }
            ],
            "cacheLoadingState": {
                "isLoaded": true,
                "loadedItemsNumber": 3558,
                "loadedSize": 2793309,
                "totalItemsNumber": 3558
            }
        }
    ]
}

getParts

This procedure returns all the information that was set for a specific parts catalog item using the upload method of the Parts Catalog API.

Parameters

Parameter Name Mandatory Type Description
items Yes Array Array of itemKey objects that identify the catalog items to get info for.
itemKey object structure

Field Mandatory Type Parts Catalog API Parameter for ‘item’ Element of ‘upload_catalog’ Request Description
catalogId Yes Integer A unique identifier of a catalog, which contains the item. Id can be retrieved using the getPartsCatalogStructure procedure.
label Yes String label A unique identifier of a part within a catalog. Can be changed after catalog update.
Response

Field Name Type Description
items Array Array of FoundItem objects. Each object represents one item whose data is available.
notFoundItems String Array of itemKey objects. Each object contains the key fields of an item whose data is not available.
foundItem object structure

Field Type Parts Catalog API Parameter for ‘item’ Element of ‘upload_catalog’ Request Description
catalogId Integer A unique identifier of a catalog, which contains the item. Id can be retrieved using the getPartsCatalogStructure procedure.
itemId Integer A unique identifier of a part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a part within a catalog.
itemType String type Item type
inventoryType String Label of a corresponding inventory type in Oracle Field Service Cloud.

Can be empty if the mapping of item types to inventory types wasn't configured in the catalog schema.

Mapping between itemType and inventoryType can be found in the typeSchemas field of the getPartsCatalogStructure procedure result.

fields Object fields An object (dictionary) which contains the item's fields by its labels.
linkedItems Array linked_items Array of LinkedItem objects.
images Array images An array of strings, where each string is a URL of an image.
linkedItem object structure

Field Type Parts Catalog API Parameter for ‘linked_item’ Element of ‘upload_catalog’ Request Description
id Integer A unique identifier of a linked part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a linked part within a catalog.
displayData String display_data Text comments to the linked item to be displayed in the user-interface.
Example of a Request
{
    "apiVersion": 1,
    "callId": "KnnXUxS7APzLBVIzY+8B0g==",
    "method": "callProcedure",
    "procedure": "getParts",
    "params": {
        "items": [
            {
                "catalogId": "2",
                "label": "Switch_model_001"
            },
            {
                "catalogId": "2",
                "label": "Switch_009"
            },
            {
                "catalogId": "4",
                "label": "FM3-2048-007"
            }
        ]
    }
}
Example of a Response
{
    "apiVersion": 1,
    "method": "callProcedureResult",
    "callId": "KnnXUxS7APzLBVIzY+8B0g==",
    "resultData": {
        "items": [
            {
                "catalogId": 2,
                "itemId": 2,
                "label": "Switch_001",
                "itemType": "switch_type",
                "inventoryType": "switch_general_eta",
                "linkedItems": [
                    {
                        "id": 3,
                        "label": "Switch_002",
                        "displayData": "better"
                    }
                ],
                "fields": {
                    "descr": "Automatic direction",
                    "model": "Switch_model_001",
                    "ports": "8 x Fast Ethernet (10/100 Mbit/s)",
                    "price": "25$",
                    "size": "151x81x33 mm,200 g",
                    "vendor": "Oracle"
                },
                "images": [
                    "https://example.com/switch_1.jpg"
                ]
            },
            {
                "catalogId": 4,
                "itemId": 3463,
                "label": "FM3-2048-007",
                "itemType": "parts",
                "inventoryType": "",
                "linkedItems": [
                    {
                        "id": 2350,
                        "label": "Z4603011",
                        "displayData": "5"
                    },
                    {
                        "id": 3160,
                        "label": "Z0293015",
                        "displayData": "7"
                    },
                ],
                "fields": {
                    "cost": "54.2346747003",
                    "description": "NETWORK I/F BOARD PCB ASSY\nFirmware update 2",
                    "item_disposition": "Repairable",
                    "item_type": "BOARD",
                    "price": "174.85",
                    "vendor": "ORCL"
                },
                "images": [
                    "https://example.com/pictures/12.jpg",
                    "https://example.com/pictures/8.jpg",
                    "https://example.com/pictures/23.jpg",
                    "https://example.com/pictures/14.jpg"
                ]
            }
        ],
        "notFoundItems": [
            {
                "catalogId": 2,
                "label": "Switch_009"
            }
        ]
    }
}

searchParts

This procedure searches for the parts in the parts catalog.

Parameters

Parameter Name Mandatory Type Description
query Yes String Search query. Minimum length - 3 symbols (spaces symbols at the beginning and at the end are trimmed), maximum length - 100 symbols.
limit No Integer Maximum number of results returned as a result.

Minimum value - 1, maximum - 1000. Default is 10.

cacheOnly No Boolean Whether the search should be done only in cache or it's allowed to make a network request to finish a search. If it's set to true then the search will be done in offline mode without any network requests.

Default is false.

Response

Field Name Type Description
items Array Array of FoundItem objects. Found parts. Limited by the limit parameter.
source String Source of the search. Possible values:
  • cache - the search was performed only in the cache, no network request was sent

  • server - the search was performed with a network request

searchId Integer A unique id of the search procedure within the particular plug-in open session. Used as a parameter for the searchPartsContinue procedure.
isContinueAvailable Boolean Indicates whether the total number of results overflows the "limit" parameter or not. If it's true, then the searchPartsContinue procedure can be used to return more results (limited by the limit parameter)
foundItem object structure

Field Type Parts Catalog API Parameter for ‘item’ Element of ‘upload_catalog’ Request Description
catalogId Integer A unique identifier of a catalog.
itemId Integer A unique identifier of a part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a part within a catalog.
itemType String type Item type
inventoryType String Label of a corresponding inventory type in Oracle Field Service Cloud.

Can be empty if the mapping of item types to inventory types wasn't configured in the catalog schema.

Mapping between itemType and inventoryType can be found in the typeSchemas field of the getPartsCatalogStructure procedure result.

fields Object fields An object (dictionary) which contains the item's fields by its labels.
linkedItems Array linked_items Array of LinkedItem objects.
images Array images An array of strings, where each string is a URL of an image.
linkedItem object structure

Field Type Parts Catalog API Parameter for ‘linked_item’ Element of ‘upload_catalog’ Request Description
id Integer A unique identifier of a linked part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a linked part within a catalog.
displayData String display_data Text comments to the linked item to be displayed in the user-interface.

Loading more results for a search

If the searchParts procedure returns isContinueAvailable = true then more search results can be loaded through the searchPartsContinue method using searchId that is returned. The searchPartsContinue method is available for 10 most recent searchId. The searchId values that are returned by the searchParts procedure are stored in a queue for 10 most recent calls that have isContinueAvailable = true. If the queue overflows, the searchId for the first call is removed and searchPartsContinue isn't available for them any more. Each call of the searchPartsContinue procedure moves its searchId to the top of the queue (makes it most recent) and when searchPartsContinue returns isContinueAvailable = false, the searchId is removed from the queue.

Example of a Request
{
    "apiVersion": 1,
    "callId": "3quvGlWIgNJlQhHrYRN4vg==",
    "method": "callProcedure",
    "procedure": "searchParts",
    "params": {
        "query": "055",
        "limit": 5
    }
}
Example of a Response
{
    "apiVersion": 1,
    "method": "callProcedureResult",
    "callId": "3quvGlWIgNJlQhHrYRN4vg==",
    "resultData": {
        "items": [
            {
                "catalogId": 3,
                "itemId": 4179,
                "label": "XG9-0552-000",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [
                    {
                        "id": 4298,
                        "label": "D3625170",
                        "displayData": "9"
                    },
                    {
                        "id": 4547,
                        "label": "D5853100",
                        "displayData": "2"
                    },
                    {
                        "id": 4824,
                        "label": "D8093048",
                        "displayData": "8"
                    },
                    {
                        "id": 6310,
                        "label": "AB014229",
                        "displayData": "7"
                    }
                ],
                "fields": {
                    "description": "BEARING NP6560",
                    "vendor": "AGHA",
                    "cost": "5.704125031",
                    "price": "22.7",
                    "item_type": "NA",
                    "item_disposition": "NA"
                },
                "images": [
                    "https://example.com/picture/15.jpg",
                    "https://example.com/picture/10.jpg",
                    "https://example.com/picture/18.jpg"
                ]
            },
            {
                "catalogId": 3,
                "itemId": 5631,
                "label": "KHB670550A00",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [],
                "fields": {
                    "description": "KID-MOD MF16, TENSION",
                    "vendor": "KODAK",
                    "cost": "742.5143066464",
                    "price": "1270.86",
                    "item_type": "NA",
                    "item_disposition": "NA"
                },
                "images": [
                    "https://example.com/picture/26.jpg"
                ]
            },
            {
                "catalogId": 3,
                "itemId": 5029,
                "label": "D0605507",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [
                    {
                        "id": 3972,
                        "label": "FB6-2374-000",
                        "displayData": "0"
                    },
                    {
                        "id": 4975,
                        "label": "B1253830",
                        "displayData": "8"
                    }
                ],
                "fields": {
                    "description": "PCB:B-C4B:SERVICE:ASS'Y",
                    "vendor": "HYTEC",
                    "cost": "1427.04",
                    "price": "2854.08",
                    "item_type": "BOARD",
                    "item_disposition": "Repairable"
                },
                "images": []
            },
            {
                "catalogId": 3,
                "itemId": 7551,
                "label": "D3305502",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [],
                "fields": {
                    "description": "[XREF TO HD3305502] DF MAIN BOARD",
                    "vendor": "NWRS",
                    "cost": "191.5",
                    "price": "480.95",
                    "item_type": "BOARD",
                    "item_disposition": "Repairable"
                },
                "images": [
                    "https://example.com/picture/2.jpg"
                ]
            },
            {
                "catalogId": 3,
                "itemId": 4203,
                "label": "D0746055",
                "itemType": "other",
                "inventoryType": "",
                "linkedItems": [
                    {
                        "id": 4037,
                        "label": "AB012067",
                        "displayData": "1"
                    }
                ],
                "fields": {
                    "description": "FLAT BELT-TRANSFER SERVICE PARTS",
                    "vendor": "SUNRISE",
                    "cost": "902.0665087976",
                    "price": "1848.46",
                    "item_type": "NA",
                    "item_disposition": "NA"
                },
                "images": [
                    "https://example.com/picture/26.jpg"
                ]
            }
        ],
        "isContinueAvailable": true,
        "source": "cache",
        "searchId": 1
    }
}

searchPartsContinue

This procedure returns additional results for a search, which is initiated by the searchParts procedure.

Parameters

Parameter Mandatory Type Description
searchId Yes Integer A unique id of the search procedure within the particular plug-in open session. Minimum value: 0, Maximum value: 2147483647 See Loading more results for a search
Response

Field Name Type Description
items Array Array of FoundItem objects. Found parts. Limited by the limit parameter for the searchParts procedure.
source String Source of the search. Possible values:
  • cache - the search was performed only in the cache, no network request was sent

  • server - the search was performed with a network request

searchId Integer A unique id of the search procedure within the particular plugin open session. Used as a parameter for the searchPartsContinue procedure.
isContinueAvailable Boolean Indicates whether the total number of results overflows the "limit" parameter or not. If it's true, then the searchPartsContinue procedure can be used to return more results (limited by the limit parameter)
foundItem object structure

Field Type Parts Catalog API Parameter for ‘item’ Element of ‘upload_catalog’ Request Description
catalogId Integer A unique identifier of a catalog.
itemId Integer A unique identifier of a part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a part within a catalog.
itemType String type Item type
inventoryType String Label of a corresponding inventory type in Oracle Field Service Cloud.

Can be empty if the mapping of item types to inventory types wasn't configured in the catalog schema.

Mapping between itemType and inventoryType can be found in the typeSchemas field of the getPartsCatalogStructure procedure result.

fields Object fields An object (dictionary) which contains the item's fields by its labels.
linkedItems Array linked_items Array of LinkedItem objects.
images Array images An array of strings, where each string is a URL of an image.
linkedItem object structure

Field Type Parts Catalog API Parameter for ‘linked_item’ Element of ‘upload_catalog’ Request Description
id Integer A unique identifier of a linked part within a catalog. Can be changed after catalog update.
label String label A unique identifier of a linked part within a catalog.
displayData String display_data Text comments to the linked item to be displayed in the user-interface.
Example of a Request
{
    "apiVersion": 1,
    "callId": "J3wa6jhKxwf6xfAZbsCdjQ==",
    "method": "callProcedure",
    "procedure": "searchPartsContinue",
    "params": {
        "searchId": 1
    }
}
Example of a Response
{
    "apiVersion": 1,
    "method": "callProcedureResult",
    "callId": "J3wa6jhKxwf6xfAZbsCdjQ==",
    "resultData": {
        "items": [
            {
                "catalogId": 3,
                "itemId": 7300,
                "label": "MU220055000",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [
                    {
                        "id": 4481,
                        "label": "CF064-67901",
                        "displayData": "0"
                    },
                    {
                        "id": 4986,
                        "label": "B2469510",
                        "displayData": "5"
                    }
                ],
                "fields": {
                    "description": "INTRACK JOGGER AY F4100-02",
                    "vendor": "KOZAK",
                    "cost": "341.4693432572",
                    "price": "799.075",
                    "item_type": "NA",
                    "item_disposition": "NA"
                },
                "images": [
                    "https://example.com/picture/4.jpg",
                    "https://example.com/picture/26.jpg",
                    "https://example.com/picture/10.jpg",
                    "https://example.com/picture/8.jpg"
                ]
            },
            {
                "catalogId": 3,
                "itemId": 6337,
                "label": "B8305562",
                "itemType": "parts",
                "inventoryType": "PT",
                "linkedItems": [],
                "fields": {
                    "description": "STEPPER MOTOR DC1 .56V 3.7W\nCatalog: #3 en Ricoh (ver 19151)",
                    "vendor": "RICOH",
                    "cost": "36.97",
                    "price": "185.7",
                    "item_type": "NA",
                    "item_disposition": "NA"
                },
                "images": [
                    "https://example.com/picture/14.jpg",
                    "https://example.com/picture/15.jpg",
                    "https://example.com/picture/4.jpg"
                ]
            }
        ],
        "isContinueAvailable": false,
        "source": "server",
        "searchId": 1
    }
}

Error Types and Error Codes

Error Types

Type When Occurs Available Message Fields
TYPE_PROCEDURE_PARAM_ITEM One or more items in the array which was sent as the value of procedure parameter have wrong contents.
  • procedure: Name of the procedure on which the error occured.

  • paramName: Name of the parameter, which is an array and whose item is invalid.

  • itemId: Number (index) of invalid items in the array starting from 0.

  • itemField

Error Codes

Type Code Caused by Procedure Error Type Cause
TYPE_PROCEDURE_PARAM_ITEM CODE_PROCEDURE_PARAM_ITEM_MANDATORY_FIELD_EMPTY getParts Validation error Mandatory field of the item is missing.
TYPE_PROCEDURE_PARAM_ITEM CODE_PROCEDURE_PARAM_ITEM_FIELD_INVALID getParts Validation error Value of item field is not valid.

Example of an Error

Request
{
    "apiVersion": 1,
    "callId": "KnnXUxS7APzLBVIzY+8B0g==",
    "method": "callProcedure",
    "procedure": "getParts",
    "params": {
        "items": [
            {
                "catalogId": "2",
                "label": "Switch_model_001"
            },
            {
                "catalogId": "2",
                "label": "Switch_model_003"
            },
            {
                "catalogId": "4",
                "label": ""
            }
        ]
    }
}
Response
{
    "apiVersion": 1,
    "callId": "KnnXUxS7APzLBVIzY+8B0g==",
    "method": "error",
    "errors": [
        {
            "type": "TYPE_PROCEDURE_PARAM_ITEM",
            "code": "CODE_PROCEDURE_PARAM_ITEM_MANDATORY_FIELD_EMPTY",
            "procedure": "getParts",
            "paramName": "items",
            "itemId": 2,
            "itemField": "label"
        }
    ]
}

A Sample Plug-In

The sample plug-in includes the following files:
  • index.html

  • styles.css

  • plugin.js

  • signature.js

  • cache.manifest

  • logo.svg

index.html File

<!DOCTYPE html>
<html manifest="cache.manifest">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Sample Plugin</title>
    <link rel="stylesheet" href="./style.css">
    <script src="//code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="signature.js"></script>
    <script src="plugin.js"></script>
    <script>
        (function($){
            $(document).ready(function(){
                var plugin = new Plugin(true);
                plugin.init();
            });
        })(jQuery);
    </script>
</head>
<body>
    <div class="header">
        <img class="header__logo" src="./logo.svg" alt="Oracle logo">
    </div>
    <h1>OFSC Sample Plugin</h1>
    <div class="content">
        <div class="section section__local-storage">
            <h2>Local Storage</h2>
            <button class="button json_local_storage_toggle" type="button">View Local Storage</button>
            <div class="json json__local-storage"></div>
        </div>
        <div class="section section__ofsc-data">
            <h2>OFSC Data</h2>
 
            <div class="row">
                <button class="button submit" type="button">Submit</button>
                <div class="back_method">and go to
                    <select class="back_method_select" title="Redirect to screen after submit">
                        <option value="default">Previous screen</option>
                        <option value="activity_by_id">Activity #</option>
                        <option value="next_activity">Next pending Activity</option>
                        <option value="activity_list">Activity List</option>
                    </select>
                    <input class="back_activity_id" type="text" title="Activity ID" placeholder="Activity ID">
                </div>
            </div>
 
            <div class="row">
                <button class="button json_request_toggle" type="button">View received JSON</button>
                <button class="button json_response_toggle" type="button">Edit JSON to send</button>
            </div>
 
            <div class="column-holder">
 
                <div class="column-item column-item--request">
                    <div class="json json__request"></div>
                </div>
 
                <div class="column-item">
                    <div class="section section--visible">
                        <h2>Inventory actions (will be applied after entity)</h2>
 
                        <!-- this part will be inserted on adding of new property -->
                        <div class="example-property item">
                            <div class="item-expander"></div>
                            <div class="key writable" contenteditable></div><span class="delimiter">: </span>
                            <div class="value value__item writable" contenteditable></div>
                            <button class="button button--remove-item">Remove</button>
                        </div>
 
                        <!-- this part will be inserted on adding of new action -->
                        <div class="example-action item">
                            <div class="item-expander"></div>
                            <div class="key action-key clickable">0</div>
                            <button class="button button--remove-item">Remove</button>
                            <br>
                            <div class="value value__collection">
                                <div class="items">
                                    <div class="item">
                                        <div class="item-expander"></div>
                                        <div class="key">action</div><span class="delimiter">: </span>
                                        <select class="value value__item writable select-inventory-action" title="">
                                            <option value="">Select action</option>
                                            <option value="create">Create</option>
                                            <option value="delete">Delete</option>
                                            <option value="install">Install</option>
                                            <option value="deinstall">Deinstall</option>
                                            <option value="undo_install">Undo install</option>
                                            <option value="undo_deinstall">Undo deinstall</option>
                                        </select>
                                    </div>
                                    <div class="item">
                                        <div class="item-expander"></div>
                                        <div class="key">entity</div><span class="delimiter">: </span>
                                        <div class="value value__item">inventory</div>
                                    </div>
 
                                    <!-- new params will be inserted here -->
 
                                    <div class="item item--excluded">
                                        <div class="item-expander"></div>
                                        <button class="button button--item-value button--add-property" type="button">Add parameter</button>
                                    </div>
 
                                    <div class="item">
                                        <div class="item-expander"></div>
                                        <div class="key">properties</div>
                                        <br>
                                        <div class="value value__collection">
                                            <div class="items">
 
                                                <!-- new properties will be inserted here -->
 
                                                <div class="item item--excluded">
                                                    <div class="item-expander"></div>
                                                    <button class="button button--item-value button--add-property" type="button">Add property</button>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
 
                        <div class="actions-form">
                            <div class="item">
                                <div class="key">actions</div>
                                <br>
                                <div class="value value__collection">
                                    <div class="items items--without-key">
 
                                        <!-- new actions will be inserted here -->
 
                                        <div class="item item--excluded">
                                            <div class="item-expander"></div>
                                            <button class="button button--item-value button--add-action" type="button">Add action</button>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
 
                    <div class="section section--visible">
                        <h2>Entity</h2>
                        <div class="form"></div>
                    </div>
                </div>
 
                <div class="column-item column-item--response">
                    <div class="json json__response" contenteditable></div>
                </div>
            </div>
 
            <div class="section section--visible">
                <h2>Entity data items</h2>
 
                <input class="data-items" type="checkbox" id="dataItems">
                <label for="dataItems">Ask OFSC to send only selected items on next open</label>
                <br>
                <div class="value value__collection data-items-holder" style="display: none;">
                    <div class="items">
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="resource" id="resource">
                                <label for="resource">Resource information</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="scheduledActivities" id="scheduledActivities">
                                <label for="scheduledActivities">Scheduled activity list</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="nonScheduledActivities" id="nonScheduledActivities">
                                <label for="nonScheduledActivities">Non-scheduled activity list</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="resourceInventories" id="resourceInventories">
                                <label for="resourceInventories">Inventories of resource</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="installedInventories" id="installedInventories">
                                <label for="installedInventories">Installed inventories</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="customerInventories" id="customerInventories">
                                <label for="customerInventories">Inventories of customer</label>
                            </div>
                        </div>
                        <div class="item">
                            <div class="item-expander"></div>
                            <div class="value value__item">
                                <input type="checkbox" value="deinstalledInventories" id="deinstalledInventories">
                                <label for="deinstalledInventories">Deinstalled inventories</label>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
 
            <div class="section section--visible">
                <h2>Background synchronization</h2>
 
                <div class="wakeup-form">
                    <div class="wakeup-form-row" id="wakeup_row">
                        <label><input type="checkbox" id="wakeup"><span class="checkbox-label">Ask OFSC to wake up the Plugin when Mobility goes online</span></label><input id="repeat_count" class="repeat" type="number" min="0" step="1" size="1" value="1">times
                    </div>
                    <div class="wakeup-form-row" id="dont_respond_row">
                        <label><input type="checkbox" id="dont_respond"><span class="checkbox-label">Don't respond on the</span></label><input id="dont_respond_on" class="repeat" type="number" min="1" step="1" size="1" value="1">wakeup
                    </div>
                </div>
 
            </div>
        </div>
 
    </div>
</body>
</html>

style.css

/*
Copyright (c) 2013, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
version: 3.18.1
*/
html{
    color:#000;
    background:#FFF;
}
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6,
pre,
code,
form,
fieldset,
legend,
input,
textarea,
p,
blockquote,
th,
td {
    margin:0;
    padding:0;
}
table {
    border-collapse:collapse;
    border-spacing:0;
}
fieldset,
img {
    border:0;
}
address,
caption,
cite,
code,
dfn,
em,
strong,
th,
var {
    font-style:normal;
    font-weight:normal;
}
 
ol,
ul {
    list-style:none;
}
 
caption,
th {
    text-align:left;
}
h1,
h2,
h3,
h4,
h5,
h6 {
    font-size:100%;
    font-weight:normal;
}
q:before,
q:after {
    content:'';
}
abbr,
acronym {
    border:0;
    font-variant:normal;
}
/* to preserve line-height and selector appearance */
sup {
    vertical-align:text-top;
}
sub {
    vertical-align:text-bottom;
}
input,
textarea,
select {
    font-family:inherit;
    font-size:inherit;
    font-weight:inherit;
    *font-size:100%; /*to enable resizing for IE*/
}
/*because legend doesn't inherit in IE */
legend {
    color:#000;
}
 
/*-------------------------------------------------------------------------*/
 
html {
    height: 100%;
}
 
body {
    font-family: Arial, serif;
    color: #444;
    background: #F0F0F0;
    min-height: 100%;
}
 
h1 {
    padding: 15px;
    font-size: 20px;
    color: #F00;
    text-align: center;
}
 
h2 {
    color: #F00;
    padding: 0 0 10px;
}
 
 
select {
    border-radius: 5px;
    padding: 5px 7px;
    font-size: 16px;
    border: 1px solid #B9B9B9;
    margin-bottom: 10px;
    vertical-align: baseline;
    background: #F1F1F1;
}
 
input {
    border-radius: 5px;
    padding: 6px 7px;
    font-size: 16px;
    border: 1px solid #B9B9B9;
    margin-bottom: 10px;
    vertical-align: baseline;
    background: #F1F1F1;
}
 
.header {
    width: 100%;
    background: #ea1b22;
    text-align: center;
    padding: 10px 15px;
    box-sizing: border-box;
}
 
.header__logo {
    width: 300px;
}
 
@media (max-width: 300px) {
    .header__logo {
        width: 100%;
    }
}
 
.content {
    padding: 0 15px;
}
 
.section {
    border: 1px solid #DEDEDE;
    background: white;
    border-radius: 5px;
    padding: 10px;
    margin: 0 0 10px;
    overflow: hidden;
    display: none;
}
 
.form {
    padding: 10px 0;
    white-space: nowrap;
    overflow: auto;
}
 
.items {
    background: url(items.png) 0 0 repeat-y;
}
 
.form > .item {
    margin-left: 0;
}
 
.item {
    padding: 0 0 0 25px;
    background: url(item.png) 0 0 no-repeat;
}
 
.item:last-child {
    background: url(item.png) 0 0 no-repeat #FFF;
}
 
.key {
    display: inline-block;
    font-weight: 700;
    margin: 4px 0;
}
 
.clickable {
    cursor: pointer;
}
 
.collapsed:after {
    content: " ...";
}
 
.delimiter {
    font-weight: 700;
}
 
.value {
    display: inline-block;
    background: none;
    border: none;
    font-size: 100%;
    white-space: pre;
    vertical-align: top;
    margin: 4px 0;
}
 
select.value {
    font-size: 16px;
    height: 19px;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    color: #444;
    padding: 0;
    border-radius: 0;
    vertical-align: baseline;
}
 
.writable {
    border-bottom: 1px dashed black;
    min-width: 60px;
}
 
.button {
    display: inline-block;
    padding: 7px 11px;
    border: 1px solid #B9B9B9;
    border-radius: 5px;
    cursor: pointer;
    outline: none;
    font-weight: bold;
    font-size: 16px;
    background: #F0F0F0;
    margin-bottom: 10px;
    margin-right: 7px;
}
 
.button__generate_sign {
    margin: 0;
    font-weight: 400;
    padding: 2px 7px;
}
 
.submit {
    background: #ee3526;
    color: #fff;
    border-color: #B50000;
}
 
.json {
    padding: 10px;
    white-space: pre;
    font-family: monospace;
    border-radius: 5px;
    margin: 0 0 10px;
    background: #353535;
    color: white;
}
 
.json__request {
    display: none;
}
 
.json__response {
    display: none;
    background: #F0F0F0;
    color: #444;
    border: 1px solid #DEDEDE;
}
 
.back_method {
    display: inline-block;
}
 
.back_activity_id {
    display: none;
}

plugin.js

"use strict";
 
(function($){
    window.Plugin = function(debugMode)
    {
        this.debugMode = debugMode || false;
        this._messageListener = null;
    };
 
    $.extend(window.Plugin.prototype,
    {
        /**
         * Dictionary of enums
         */
        dictionary: {
            astatus: {
                pending: {
                    label: 'pending',
                    translation: 'Pending',
                    outs: ['started', 'cancelled'],
                    color: '#FFDE00'
                },
                started: {
                    label: 'started',
                    translation: 'Started',
                    outs: ['complete', 'suspended', 'notdone', 'cancelled'],
                    color: '#A2DE61'
                },
                complete: {
                    label: 'complete',
                    translation: 'Completed',
                    outs: [],
                    color: '#79B6EB'
                },
                suspended: {
                    label: 'suspended',
                    translation: 'Suspended',
                    outs: [],
                    color: '#9FF'
                },
                notdone: {
                    label: 'notdone',
                    translation: 'Not done',
                    outs: [],
                    color: '#60CECE'
                },
                cancelled: {
                    label: 'cancelled',
                    translation: 'Cancelled',
                    outs: [],
                    color: '#80FF80'
                }
            },
            invpool: {
                customer: {
                    label: 'customer',
                    translation: 'Customer',
                    outs: ['deinstall'],
                    color: '#04D330'
                },
                install: {
                    label: 'install',
                    translation: 'Installed',
                    outs: ['provider'],
                    color: '#00A6F0'
                },
                deinstall: {
                    label: 'deinstall',
                    translation: 'Deinstalled',
                    outs: ['customer'],
                    color: '#00F8E8'
                },
                provider: {
                    label: 'provider',
                    translation: 'Resource',
                    outs: ['install'],
                    color: '#FFE43B'
                }
            }
        },
 
        /**
         * Which field shouldn't be editable
         *
         * format:
         *
         * parent: {
         *     key: true|false
         * }
         *
         */
        renderReadOnlyFieldsByParent: {
            data: {
                apiVersion: true,
                method: true,
                entity: true
            },
            resource: {
                pid: true,
                pname: true,
                gender: true
            }
        },
 
        /**
         * Check for string is valid JSON
         *
         * @param {*} str - String that should be validated
         *
         * @returns {boolean}
         *
         * @private
         */
        _isJson: function(str)
        {
            try
            {
                JSON.parse(str);
            }
            catch (e)
            {
                return false;
            }
            return true;
        },
 
        /**
         * Return origin of URL (protocol + domain)
         *
         * @param {String} url
         *
         * @returns {String}
         *
         * @private
         */
        _getOrigin: function(url)
        {
            if (url != '')
            {
                if (url.indexOf("://") > -1)
                {
                    return 'https://' + url.split('/')[2];
                }
                else
                {
                    return 'https://' + url.split('/')[0];
                }
            }
 
            return '';
        },
 
        /**
         * Return domain of URL
         *
         * @param {String} url
         *
         * @returns {String}
         *
         * @private
         */
        _getDomain: function(url)
        {
            if (url != '')
            {
                if (url.indexOf("://") > -1)
                {
                    return url.split('/')[2];
                }
                else
                {
                    return url.split('/')[0];
                }
            }
 
            return '';
        },
 
        /**
         * Sends postMessage to document.referrer
         *
         * @param {Object} data - Data that will be sent
         *
         * @private
         */
        _sendPostMessageData: function(data)
        {
            if (document.referrer !== '')
            {
                this._log(window.location.host + ' -> ' + data.method + ' ' + this._getDomain(document.referrer), JSON.stringify(data, null, 4));
 
                parent.postMessage(JSON.stringify(data), this._getOrigin(document.referrer));
            }
        },
 
        /**
         * Handles during receiving postMessage
         *
         * @param {MessageEvent} event - Javascript event
         *
         * @private
         */
        _getPostMessageData: function(event)
        {
            if (typeof event.data !== 'undefined')
            {
                if (this._isJson(event.data))
                {
                    var data = JSON.parse(event.data);
 
                    if (data.method)
                    {
                        this._log(window.location.host + ' <- ' + data.method + ' ' + this._getDomain(event.origin), JSON.stringify(data, null, 4));
 
                        switch (data.method)
                        {
                            case 'open':
                                this.pluginOpen(data);
 
                                break;
                            case 'error':
                                data.errors = data.errors || {error: 'Unknown error'};
                                this._showError(data.errors);
 
                                break;
                            default:
                                alert('Unknown method');
 
                                break;
                        }
                    }
                    else
                    {
                        this._log(window.location.host + ' <- NO METHOD ' + this._getDomain(event.origin), null, null, true);
                    }
                }
                else
                {
                    this._log(window.location.host + ' <- NOT JSON ' + this._getDomain(event.origin), null, null, true);
                }
            }
            else
            {
                this._log(window.location.host + ' <- NO DATA ' + this._getDomain(event.origin), null, null, true);
            }
        },
 
        /**
         * Show alert with error
         *
         * @param {Object} errorData - Object with errors
         *
         * @private
         */
        _showError: function(errorData)
        {
            alert(JSON.stringify(errorData, null, 4));
        },
 
        /**
         * Logs to console
         *
         * @param {String} title - Message that will be log
         * @param {String} [data] - Formatted data that will be collapsed
         * @param {String} [color] - Color in Hex format
         * @param {Boolean} [warning] - Is it warning message?
         *
         * @private
         */
        _log: function(title, data, color, warning)
        {
            if (!this.debugMode)
            {
                return;
            }
            if (!color)
            {
                color = '#0066FF';
            }
            if (!!data)
            {
                console.groupCollapsed('%c[Plugin API] ' + title, 'color: ' + color + '; ' + (!!warning ? 'font-weight: bold;' : 'font-weight: normal;'));
                console.log('[Plugin API] ' + data);
                console.groupEnd();
            }
            else
            {
                console.log('%c[Plugin API] ' + title, 'color: ' + color + '; ' + (!!warning ? 'font-weight: bold;' : ''));
            }
        },
 
        /**
         * Business login on plugin init
         */
        pluginInit: function()
        {
            var data = {
                initTime: new Date().getTime()
            };
 
            this._log(window.location.host + ' INIT. SET DATA TO LOCAL STORAGE', JSON.stringify(data, null, 4));
 
            localStorage.setItem('pluginInitData', JSON.stringify(data));
        },
 
        /**
         * Business login on plugin open
         *
         * @param {Object} receivedData - JSON object that contain data from OFSC
         */
        pluginOpen: function(receivedData)
        {
            this._log(window.location.host + ' OPEN. GET DATA FROM LOCAL STORAGE', JSON.stringify(JSON.parse(localStorage.getItem('pluginInitData')), null, 4));
            $('.json__local-storage').text(localStorage.getItem('pluginInitData'));
            $('.section__local-storage').show();
 
            $('.form').html(this.renderForm(receivedData));
 
            $('.key').each(function(index, item)
            {
                if ($(item).siblings('.value').has('.items').size() !== 0)
                {
                    $(item).addClass('clickable');
                }
            }).on('click', function()
            {
                if ($(this).siblings('.value').has('.items').size() !== 0)
                {
                    $(this).siblings('.value').toggle();
                    $(this).toggleClass('collapsed');
                }
            });
 
            $('.button__generate_sign').on('click', function(e)
            {
                var canvasElement = $('<canvas>').addClass('value').attr({height: 240, width: 320}).get(0);
                $(e.target).after(canvasElement);
                drawSampleSignature(canvasElement);
 
                $(e.target).parents('.item').addClass('edited');
 
                this._updateResponseJSON();
 
                $(e.target).remove();
            }.bind(this));
 
            $('.value__item').on('input, change', function(e)
            { //IE10+
                $(e.target).parents('.item').addClass('edited');
 
                this._updateResponseJSON();
            }.bind(this));
 
            $('.back_method_select, .back_activity_id').on('change', function(e)
            { //IE10+
                this._updateResponseJSON();
            }.bind(this));
 
            $('.json__request').text(JSON.stringify(receivedData, null, 4));
 
            $('.submit').click(function()
            {
                var json_response = $('.json__response');
                if (json_response.is(":hidden") === true)
                {
                    var form = this.parseForm($('.form'));
                    this._sendPostMessageData(form.data);
                }
                else
                {
                    if (this._isJson(json_response.text()))
                    {
                        var data = JSON.parse(json_response.text());
                        this._sendPostMessageData(data);
                    }
                    else
                    {
                        alert('JSON parse error!');
                    }
                }
            }.bind(this));
 
            $('.section__ofsc-data').show();
        },
 
        /**
         * Render JSON object to DOM
         *
         * @param {Object} data - JSON object
         *
         * @returns {jQuery}
         */
        renderForm: function(data)
        {
            return this.renderCollection('data', data, true);
        },
 
        /**
         * Render JSON object to follow HTML:
         *
         * <div class="item">
         *     <div class="key">{key}</div>
         *     <div class="value">{value}</div>
         * </div>
         * <div class="item">
         *     <div class="key">{key}</div>
         *     <div class="value">
         *         <div class="items">
         *              <div class="item">
         *                  <div class="key">{key}</div>
         *                  <div class="value">{value}</div>
         *              </div>
         *              <div class="item">
         *                  <div class="key">{key}</div>
         *                  <div class="value">{value}</div>
         *              </div>
         *              ...
         *         </div>
         *     </div>
         * </div>
         * ...
         *
         * @param {String} key - Collection name
         * @param {Object} items - Child items of collection
         * @param {Boolean} [isWritable] - Will render as writable?
         * @param {number} [level] - Level of recursion
         * @param {string} [parentKey] - parent Key
         *
         * @returns {jQuery}
         */
        renderCollection: function(key, items, isWritable, level, parentKey)
        {
            var render_item = $('<div>').addClass('item');
            var render_key = $('<div>').addClass('key').text(key);
            var render_value = $('<div>').addClass('value value__collection');
            var render_items = $('<div>').addClass('items');
 
            isWritable = isWritable || false;
            level = level || 1;
            parentKey = parentKey || '';
 
            var newParentKey = key;
 
            if (items)
            {
                $.each(items, function(key, value)
                {
                    if (value && typeof value === 'object')
                    {
                        render_items.append(this.renderCollection(key, value, isWritable, level + 1, newParentKey));
                    }
                    else
                    {
                        render_items.append(this.renderItem(key, value, isWritable, level + 1, newParentKey).get(0));
                    }
                }.bind(this));
            }
 
            render_item.append(render_key)/*.append('<span>: </span>')*/;
 
            render_value.append(render_items);
            render_item.append($('<br>'));
            render_item.append(render_value);
 
            return render_item;
 
        },
 
        /**
         * Render key and value to follow HTML:
         *
         * <div class="item">
         *     <div class="key">{key}</div>
         *     <div class="value">{value}</div>
         * </div>
         *
         * @param {String} key - Key
         * @param {String} value - Value
         * @param {Boolean} [isWritable] - Will render as writable?
         * @param {number} [level] - Level of recursion
         * @param {string} [parentKey] - parent Key
         *
         * @returns {jQuery}
         */
        renderItem: function(key, value, isWritable, level, parentKey)
        {
            var render_item = $('<div>').addClass('item');
            var render_value;
            var render_key;
 
            isWritable = isWritable || false;
            level = level || 1;
            parentKey = parentKey || '';
 
            render_key = $('<div>').addClass('key').text(key);
            render_item.append(render_key).append('<span class="delimiter">: </span>');
 
            if (value === null)
            {
                value = '';
            }
 
            if (typeof this.renderReadOnlyFieldsByParent[parentKey] !== 'undefined' && typeof this.renderReadOnlyFieldsByParent[parentKey][key] !== 'undefined' && this.renderReadOnlyFieldsByParent[parentKey][key] === true)
            {
                isWritable = false;
            }
 
            switch (key)
            {
                case "csign":
                    if (isWritable)
                    {
                        render_value = $('<button>').addClass('button but-ton__generate_sign').text('Generate');
                    }
                    break;
                default:
                    if (this.dictionary[key])
                    {
                        render_value = this.renderSelect(this.dictionary, key, value, isWritable).addClass('value value__item');
                    }
                    else
                    {
                        render_value = $('<div>').addClass('value val-ue__item').text(value);
                        if (isWritable)
                        {
                            ren-der_value.addClass('writable').attr('contenteditable', true);
                        }
                    }
 
                    break;
            }
            render_item.append(render_value);
 
            return render_item;
        },
 
        /**
         * Render enums
         *
         * <select class="value [writable]" [disabled]>
         *     <option value="{value}" [selected]>{dictionary}</option>
         *     ...
         * </select>
         *
         * @param {Object} dictionary - Dictionary that will be used for Enum rendering
         * @param {String} key - Just field name
         * @param {String} value - Selected value
         * @param {Boolean} isWritable - Will render as writable?
         *
         * @returns {HTMLElement}
         */
        renderSelect: function(dictionary, key, value, isWritable)
        {
            var render_value;
 
            var outs = dictionary[key][value].outs;
            var allowedValues = [value].concat(outs);
            var disabled = '';
 
            render_value = $('<select>').css({background: diction-ary[key][value].color});
 
            if (isWritable)
            {
                render_value.addClass('writable');
            }
 
            if (!outs.length || !isWritable)
            {
                render_value.attr('disabled', true);
                render_value.removeClass('writable');
            }
 
            $.each(allowedValues, function(index, label)
            {
                render_value.append('<option' + (label === value ? ' selected' : '') + ' value="' + dictionary[key][label].label + '">' + diction-ary[key][label].translation + '</option>');
            });
 
            return render_value;
        },
 
        /**
         * Parse form (root HTML element that was rendered)
         *
         * @param {HTMLElement} element - root HTML element
         *
         * @returns {Object}
         */
        parseForm: function(element)
        {
            var form = {};
 
            form.data = {
                apiVersion: 1,
                method: 'close',
                backScreen: $('.back_method_select').val()
            };
 
            if (form.data.backScreen === 'activity_by_id')
            {
                $.extend(form.data, {
                    backActivityId: $('.back_activity_id').val()
                });
            }
 
            $.extend(form.data, this.parseCollection(element).data);
 
            delete form.data.entity;
            delete form.data.resource;
 
            return form;
        },
 
        /**
         * Convert HTML elements to JSON
         *
         * @param {HTMLElement} rootElement - Root element that should be parsed recursively
         *
         * @returns {Object}
         *
         * <div class="key">activity</div>
         * <div class="value value__collection">
         *     <div class="items"> <-------------------------------- rootElement !!!
         *         <div class="item edited">
         *             <div class="key">WO_COMMENTS</div>
         *             <div class="value">text_comments</div>
         *         </div>
         *         <div class="item">
         *             <div class="key">aid</div>
         *             <div class="value">4225274</div>
         *         </div>
         *         <div class="item">
         *             <div class="key">caddress</div>
         *             <div class="value">text_address</div>
         *         </div>
         *     </div>
         * </div>
         *
         * converts to:
         *
         * {
         *     "aid": "4225274",
         *     "WO_COMMENTS": "text_comments"
         * }
         *
         */
        parseCollection: function(rootElement)
        {
 
            var returnObject = {};
 
            $(rootElement).children('.item').each(function(itemIndex, item)
            {
                var parentKey;
                var valueKey;
                var value;
                var mandatoryField = false;
 
                parentKey = $(rootElement).parent().siblings('.key').get(0);
                valueKey = $(item).children('.key').get(0);
 
                //Logic of mandatory fields
                if ((parentKey !== undefined) && (
                    ($(parentKey).text() == 'activity' && $(valueKey).text() == 'aid') ||
                    ($(parentKey).text() == 'inventory' && $(valueKey).text() == 'invid')
                ))
                {
                    mandatoryField = true;
                }
 
                if ($(item).hasClass('item') === true && ($(item).hasClass('edited') === true || mandatoryField))
                {
 
                    value = $(item).children('.value').get(0);
 
                    if ($(value).children('.items').size() > 0)
                    {
                        returnObject[$(valueKey).text()] = this.parseCollection($(value).children('.items').get(0));
                    }
                    else
                    {
                        switch ($(value).prop("tagName"))
                        {
                            case 'SELECT':
                                returnObject[$(valueKey).text()] = $(val-ue).val();
                                break;
                            case 'CANVAS':
                                returnObject[$(valueKey).text()] = val-ue.toDataURL();
                                break;
                            default:
                                returnObject[$(valueKey).text()] = $(val-ue).text();
                                break;
                        }
                    }
                }
            }.bind(this));
 
            return returnObject;
        },
 
        /**
         * Update JSON
         *
         * @private
         */
        _updateResponseJSON: function()
        {
            var form = this.parseForm($('.form'));
            $('.json__response').text(JSON.stringify(form.data, null, 4));
        },
 
        /**
         * Initialization function
         */
        init: function()
        {
            $('.back_method_select').change(function()
            {
                if ($('.back_method_select').val() == 'activity_by_id')
                {
                    $('.back_activity_id').show();
                }
                else
                {
                    $('.back_activity_id').val('').hide();
                }
            });
 
            $('.json_request_toggle').click(function()
            {
                $('.json__response').hide();
                $('.json__request').toggle();
            });
 
            $('.json_response_toggle').click(function()
            {
                $('.json__request').hide();
                this._updateResponseJSON();
                $('.json__response').toggle();
            }.bind(this));
 
            this._messageListener =  this._getPostMessageData.bind(this);
 
            window.addEventListener("message", this._messageListener, false); //Only IE9+
 
            this.pluginInit();
 
            this._sendPostMessageData({
                apiVersion: 1,
                method: 'ready'
            });
        }
    });
 
})(jQuery);

signature.js

function drawSampleSignature(canvas)
{   if (!canvas.getContext)
    {
        return;
    }
     var c = canvas.getContext('2d');
 
    c.fillStyle="#ffffff";
    c.strokeStyle = "#000000";
    c.lineWidth = 1.5;
    c.lineCap = "round";
 
    // White background
    c.rect(0, 0, 320, 230);
    c.fill();
 
    c.beginPath();
    // C
    c.moveTo(38, 57);
    c.bezierCurveTo(38, 57, 39, 78, 44, 77);
    c.bezierCurveTo(50, 76, 58, 21, 43, 21);
    c.bezierCurveTo(26, 21, 20, 119, 35, 120);
    c.bezierCurveTo(50, 120, 68, 91, 77, 65);
    // usto
    c.moveTo(66, 76);
    c.bezierCurveTo(66, 76, 67, 112, 71, 111);
    c.bezierCurveTo(75, 110, 80, 77, 81, 76);
    c.bezierCurveTo(82, 74, 78, 100, 84, 100);
    c.bezierCurveTo(87, 100, 95, 73, 95, 70);
    c.bezierCurveTo(96, 66, 79, 63, 90, 84);
    c.bezierCurveTo(95, 94, 100, 90, 111, 102);
    c.bezierCurveTo(115, 107, 96, 121, 96, 118);
    c.bezierCurveTo(97, 108, 108, 101, 113, 86);
    c.bezierCurveTo(118, 72, 117, 38, 118, 45);
    c.bezierCurveTo(119, 52, 126, 114, 129, 111);
    c.bezierCurveTo(130, 110, 121, 88, 114, 89);
    c.bezierCurveTo(108, 89, 133, 87, 138, 77);
    c.bezierCurveTo(142, 66, 148, 76, 148, 81);
    c.bezierCurveTo(149, 86, 149, 95, 145, 95);
    c.bezierCurveTo(137, 95, 138, 77, 138, 77);
    // mer
    c.moveTo(149, 87);
    c.bezierCurveTo(149, 87, 151, 72, 153, 71);
    c.bezierCurveTo(155, 71, 158, 91, 159, 95);
    c.bezierCurveTo(160, 99, 158, 68, 161, 69);
    c.bezierCurveTo(164, 69, 161, 85, 164, 84);
    c.bezierCurveTo(166, 84, 164, 66, 166, 67);
    c.bezierCurveTo(168, 67, 170, 89, 176, 87);
    c.bezierCurveTo(182, 86, 186, 52, 180, 52);
    c.bezierCurveTo(175, 51, 173, 84, 194, 89);
    c.bezierCurveTo(209, 93, 190, 64, 202, 61);
    c.bezierCurveTo(209, 60, 208, 72, 213, 71);
    c.bezierCurveTo(215, 71, 212, 61, 214, 60);
    c.bezierCurveTo(215, 58, 208, 100, 215, 98);
    c.bezierCurveTo(222, 95, 243, 64, 245, 57);
    // S
    c.moveTo(137, 131);
    c.bezierCurveTo(143, 122, 123, 106, 117, 127);
    c.bezierCurveTo(112, 147, 131, 157, 138, 161);
    c.bezierCurveTo(152, 169, 138, 181, 126, 184);
    c.bezierCurveTo(116, 187, 123, 179, 123, 179);
    // i
    c.moveTo(148, 149);
    c.bezierCurveTo(148, 149, 147, 152, 149, 153);
    c.moveTo(152, 158);
    c.bezierCurveTo(156, 167, 150, 183, 153, 184);
    // gna
    c.moveTo(170, 160);
    c.bezierCurveTo(170, 160, 166, 151, 162, 152);
    c.bezierCurveTo(158, 153, 160, 168, 164, 168);
    c.bezierCurveTo(168, 168, 174, 165, 170, 152);
    c.bezierCurveTo(167, 140, 181, 187, 180, 199);
    c.bezierCurveTo(180, 215, 164, 219, 164, 202);
    c.bezierCurveTo(165, 194, 182, 168, 183, 154);
    c.bezierCurveTo(184, 148, 176, 184, 182, 184);
    c.bezierCurveTo(187, 185, 184, 159, 186, 161);
    c.bezierCurveTo(188, 162, 189, 175, 193, 174);
    c.bezierCurveTo(196, 173, 195, 156, 199, 155);
    c.bezierCurveTo(202, 153, 207, 164, 205, 169);
    c.bezierCurveTo(203, 175, 196, 171, 196, 163);
    c.bezierCurveTo(197, 155, 208, 169, 207, 155);
    c.bezierCurveTo(207, 143, 211, 171, 215, 169);
    c.bezierCurveTo(218, 167, 215, 153, 216, 153);
    // t
    c.moveTo(218, 132);
    c.bezierCurveTo(222, 127, 222, 174, 227, 175);
    c.bezierCurveTo(231, 176, 233, 171, 233, 171);
    // -ure
    c.moveTo(212, 156);
    c.bezierCurveTo(212, 156, 231, 143, 234, 144);
    c.bezierCurveTo(236, 144, 234, 162, 238, 162);
    c.bezierCurveTo(243, 162, 242, 145, 244, 146);
    c.bezierCurveTo(247, 146, 247, 158, 249, 158);
    c.bezierCurveTo(251, 158, 249, 137, 251, 138);
    c.bezierCurveTo(254, 139, 252, 142, 256, 143);
    c.bezierCurveTo(259, 143, 254, 168, 269, 161);
    c.bezierCurveTo(284, 154, 271, 127, 268, 126);
    c.bezierCurveTo(266, 125, 260, 139, 274, 157);
    c.bezierCurveTo(288, 175, 298, 173, 298, 173);
    c.stroke();
}

cache.manifest

CACHE:
./index.html
./style.css
./plugin.js
./signature.js
./logo.svg
//code.jquery.com/jquery-2.1.4.min.js
 
 
FALLBACK:
 
 
NETWORK:
*

logo.svg

<svg xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" version="1.0" width="662.84644"
height="94.145668" id="svg115845">
  <defs id="defs115847">
    <clipPath id="clp82">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path1826"/>
    </clipPath>
    <clipPath id="clp83">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path1835"/>
    </clipPath>
    <clipPath id="clp84">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path1844"/>
    </clipPath>
    <clipPath id="clp81">
      <path
d="M 1000.9,934.34 L 1038.6,934.34 L 1038.6,922.24 L 1000.9,922.24 L 1000.9,934.34 z "
id="path1800"/>
    </clipPath>
    <clipPath id="clipPath116030">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path116032"/>
    </clipPath>
    <clipPath id="clipPath116038">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path116040"/>
    </clipPath>
    <clipPath id="clipPath116046">
      <path
d="M 1001.6,870.49 L 1036.3,870.49 L 1036.3,857.41 L 1001.6,857.41 L 1001.6,870.49 z "
id="path116048"/>
    </clipPath>
  </defs>
  <g transform="translate(-702.6538,-712.5837)" id="layer1">
    <g id="g16337">
      <path
d="M 980.65099,771.70039 L 1021.3029,771.70039 L 999.80762,737.1177 L 960.35637,799.64472 L 942.40142,799.64472 L 990.38729,724.53644 C 992.47368,721.50175 995.95082,719.66834 999.80762,719.66834 C 1003.5375,719.66834 1007.0147,721.43856 1009.0379,724.41 L 1057.2134,799.64472 L 1039.2584,799.64472 L 1030.7865,785.67256 L 989.62847,785.67256 L 980.65099,771.70039 z M 1167.1573,785.67256 L 1167.1573,720.42701 L 1151.9207,720.42701 L 1151.9207,792.05805 C 1151.9207,794.01795 1152.6795,795.9146 1154.1335,797.3687 C 1155.5874,798.82285 1157.5474,799.64472 1159.697,799.64472 L 1229.1786,799.64472 L 1238.1561,785.67256 L 1167.1573,785.67256 z M 915.08933,773.97641 C 929.88361,773.97641 941.89588,762.02739 941.89588,747.23331 C 941.89588,732.43928 929.88361,720.42701 915.08933,720.42701 L 848.43367,720.42701 L 848.43367,799.64472 L 863.66423,799.64472 L 863.66423,734.39918 L 914.07773,734.39918 C 921.15891,734.39918 926.84882,740.15238 926.84882,747.23331 C 926.84882,754.31423 921.15891,760.06749 914.07773,760.06749 L 871.12457,760.00424 L 916.60647,799.64472 L 938.7347,799.64472 L 908.13505,773.97641 L 915.08933,773.97641 z M 754.67521,799.64472 C 732.80632,799.64472 715.05966,781.94244 715.05966,760.06749 C 715.05966,738.19249 732.80632,720.42701 754.67521,720.42701 L 800.71978,720.42701 C 822.59473,720.42701 840.32876,738.19249 840.32876,760.06749 C 840.32876,781.94244 822.59473,799.64472 800.71978,799.64472 L 754.67521,799.64472 z M 799.69555,785.67256 C 813.86396,785.67256 825.33883,774.22928 825.33883,760.06749 C 825.33883,745.90564 813.86396,734.39918 799.69555,734.39918 L 755.69287,734.39918 C 741.53103,734.39918 730.04958,745.90564 730.04958,760.06749 C 730.04958,774.22928 741.53103,785.67256 755.69287,785.67256 L 799.69555,785.67256 z M 1089.0142,799.64472 C 1067.1392,799.64472 1049.3739,781.94244 1049.3739,760.06749 C 1049.3739,738.19249 1067.1392,720.42701 1089.0142,720.42701 L 1143.7016,720.42701 L 1134.7873,734.39918 L 1090.0258,734.39918 C 1075.8639,734.39918 1064.3577,745.90564 1064.3577,760.06749 C 1064.3577,774.22928 1075.8639,785.67256 1090.0258,785.67256 L 1144.9659,785.67256 L 1135.9885,799.64472 L 1089.0142,799.64472 z M 1275.3309,785.67256 C 1263.6346,785.67256 1253.7087,777.83296 1250.6739,767.02192 L 1315.7932,767.02192 L 1324.7707,753.04976 L 1250.6739,753.04976 C 1253.7087,742.30196 1263.6346,734.39918 1275.3309,734.39918 L 1320.0292,734.39918 L 1329.0699,720.42701 L 1274.3193,720.42701 C 1252.4443,720.42701 1234.679,738.19249 1234.679,760.06749 C 1234.679,781.94244 1252.4443,799.64472 1274.3193,799.64472 L 1321.2936,799.64472 L 1330.271,785.67256 L 1275.3309,785.67256"
id="path16197" style="fill:#fff;fill-rule:nonzero;stroke:none"/>
      <path
d="M 1337.2258,728.8356 C 1337.2258,724.97899 1340.3233,721.88111 1344.1801,721.88111 C 1348.1001,721.88111 1351.1976,724.97899 1351.1976,728.8356 C 1351.1976,732.75534 1348.1001,735.85328 1344.1801,735.85328 C 1340.3233,735.85328 1337.2258,732.75534 1337.2258,728.8356 z M 1344.1801,737.81317 C 1349.1112,737.81317 1353.0944,733.83013 1353.0944,728.89879 C 1353.0944,723.96745 1349.1112,719.98446 1344.1801,719.98446 C 1339.3117,719.98446 1335.329,723.96745 1335.329,728.89879 C 1335.329,733.83013 1339.3117,737.81317 1344.1801,737.81317 z M 1343.3581,723.58814 C 1344.7489,723.58814 1345.3181,723.65133 1345.9505,723.9042 C 1347.7205,724.47325 1347.91,726.05378 1347.91,726.68602 C 1347.91,726.81246 1347.91,727.12857 1347.7836,727.50788 C 1347.7205,727.88725 1347.4677,728.64592 1346.5825,729.21491 C 1346.4561,729.27815 1346.3929,729.34135 1346.1401,729.46778 L 1348.4161,733.57726 L 1346.2033,733.57726 L 1344.1801,729.7839 L 1342.7894,729.7839 L 1342.7894,733.57726 L 1340.8294,733.57726 L 1340.8294,723.58814 L 1343.3581,723.58814 z M 1344.0537,728.14012 C 1344.6857,728.07693 1345.3181,728.07693 1345.6973,727.50788 C 1345.8868,727.25501 1345.9505,727.00214 1345.9505,726.62277 C 1345.9505,726.11703 1345.6341,725.67447 1345.1917,725.42155 C 1344.7489,725.23192 1344.3065,725.23192 1343.3581,725.23192 L 1342.7894,725.23192 L 1342.7894,728.14012 L 1344.0537,728.14012"
id="path16199" style="fill:#fff;fill-rule:nonzero;stroke:none"/>
    </g>
  </g>
</svg>

Upgrading from Previous Versions

Suppose you have created a plug-in API for a specific version of Oracle Field Service Cloud and Oracle Field Service Cloud is upgraded with the next version. You must upgrade your plug-in API to make it compatible with the latest release of Oracle Field Service Cloud.

You can upgrade your plug-ins to version 16.2 according to the following rules:
  • Existing external plug-ins will continue functioning according to their settings; their type will change from External to HTML5 Application.

  • You can edit the settings of the existing external plug-ins in version 16.2.

    Caution: Selecting the Use Plugin API check box for a plug-in created in a previous version makes the plug-in unusable.
  • Existing internal plug-ins will continue functioning according to their settings.

  • You cannot edit the settings of the existing internal plug-ins; they will be displayed as Read-Only.

  • No new internal plug-ins can be created.

The plug-in API now accepts raw JS objects as values for PostMessage data. Original JSON strings are still supported, so backward compatibility with the existing plug-ins framework that were implemented in release 17.2 are retained. However, file properties cannot be updated in this case.

Accessing Oracle Field Service Cloud Public API

To avoid cross-domain communication blocking when an Oracle Field Service Cloud API is called from a plugin:
  • For Oracle Field Service Cloud hosted plug-ins: When calling an Oracle Field Service Cloud API, the plug-in must use a plug-in hosting domain (available in Java script as a value of window.location.hostname property) instead of api.etadirect.com.

  • For externally hosted plug-ins: The plug-in must not call an Oracle Field Service Cloud API directly from the browser. Instead, the plug-in must call its server side. All the API calls must be performed by the server side and the call results transmitted to the plug-in.