Follow these instructions to create destination rules that determine what actions the ServiceForms Connector should take when it receives a filled-out form from a technician. Repeat these steps for every Connector rule that needs to be added. Typically you will only need one, even if you want that Connector rule to take multiple actions (such as creating assets AND creating deficiencies).

Create Destination Rules

Step 1: Go to the ServiceForms Connector URL serviceforms.servicetrade.com.

Step 2: If you have not already done so, log in with the ServiceTrade username/password of a user that has been granted the Admin Account activity.

Step 3: You should see a list of forms, and the newly created form should appear there. Click on it.

Step 4: On the form details page, click ‘Add Destination Rule’.

Step 5: In the ‘Destination Type’ dropdown, choose a destination type. Currently the only possible choice is ‘Update ServiceTrade’.

Step 6: In the ‘Destination Name’ input box, enter a name that describes the actions that will be taken by this rule (for instance, ‘Create assets and deficiencies’.

Step 7: In the ‘Destination Rule’ box, enter the destination rule code.*

*For more information on coding destination rules, see Destination Rule Reference section below.

Step 8: Click ‘Save Destination’ to save the destination rule.

Destination Rule Reference

Each destination rule is defined as a block of JavaScript code. The SF namespace provides the following properties (listed with their descriptions):

All destination rule code is executed inside a Node vm2 sandbox. In addition to the SF namespace, the following external modules are available:

Destination rule method signatures

All methods are asynchronous.

Each destination rule is executed inside an asynchronous function, so await should be used for asynchronous calls (such as the SF create and update methods).

Comments

ALL comments should be created with multiline format:

/* This is a good comment */
/*
This is
also a
good comment
*/
// This is a bad comment that will make your destination rule fail.

Destination Rule Methods

These methods can be called inside a destination rule to create/update data inside ServiceTrade.

createAssets(assetsArray)

Creates a set of assets from a given array. Each array member should have the following properties:

  • locationId (int) - ID of location to which asset should be added [REQUIRED]
  • type (enum, one of the types listed in GET /api/assetDefinition) [REQUIRED]
  • parentId (int) - ID of the newly created asset’s parent. If not provided, the building asset will be the parent.
  • properties (object -- contents vary by asset definition) [REQUIRED]

Returns an array of created asset objects.

For each asset, this method will construct an API call like:

let assetPayload = {
locationId: locationId,
type: type,
properties: properties
};
servicetrade.post('/asset’, assetPayload);

updateAssets(assetsArray)

Updates a set of assets from a given array. Each array member should have the following properties:

  • assetId (int) - ID of the asset to be updated [REQUIRED]
  • properties (object -- contents vary by asset definition)
  • status (enum, one of: ‘active’, ‘inactive’)

Returns an array of updated assets.

For each asset, this method will construct an API call like:

let assetPayload = {
status: status,
properties: properties
};
servicetrade.put('/asset/’ + assetId, assetPayload);

createJobItems(jobItemsArray)

Creates a set of job items from a given array. Each array member should have the following properties:

  • jobId (int) - ID of the job to which the job item should be added [REQUIRED]
  • libItemId (int) - ID of lib item to use when creating the job item [REQUIRED, unless ‘name’ and ‘serviceLineId’ are provided]
  • name (string) [REQUIRED, unless ‘libItemId’ is provided]
  • serviceLineId (int) - ID of service line to use when creating the job item [REQUIRED, unless ‘libItemId’ is provided AND referenced lib item has a service line assignment]
  • quantity (float) [REQUIRED]
  • serviceRequestId (int) - ID of the service request to which the job item should be associated
  • source (object - see job item API documentation for details)

For each job item, this method will construct an API call like:

let jobItemPayload = {
jobId: jobId,
libItemId: libItemId,
name: name,
serviceLineId: serviceLineId,
serviceRequestId: serviceRequestId,
quantity: quantity,
source: source,
usedOn: Moment().format(‘X’) // Always today
};
servicetrade.post('/jobitem’, jobItemPayload);

createJobComments(jobCommentsArray)

Creates a set of job comments from a given array. Each array member should have the following properties:

  • jobId (int) - ID of the job to which the comment should be added [REQUIRED]
  • content (string) - the comment of the content [REQUIRED]
  • visibility (array) - an array of one or more visibility flags. Possible options are: ‘public’, ‘tech’, ‘schedule'. If not provided, the account default visibility settings for comments will be used.

For each job comment, this method will construct an API call like:

let jobCommentPayload = {
entityId: jobId,
entityType: 3,
content: content,
visibility: visibility
};
servicetrade.post('/comment’, jobCommentPayload);

createJobServices(jobServicesArray)

Creates a set of job services from a given array. Each array member should have the following properties:

  • jobId (int) - ID of the job to which the service should be added [REQUIRED]
  • locationId (int) - ID of the job to which the location should be added [REQUIRED]
  • windowStart (Unix timestamp) - the Unix timestamp of the beginning of the service’s due window [REQUIRED]
  • windowEnd (Unix timestamp) - the Unix timestamp of the end of the service’s due window [REQUIRED]
  • serviceLineId (int) - ID of service line to use when creating the service [REQUIRED]
  • assetId (int) - ID of the asset associated with the service
  • status (string) - the status of the service; if not provided, defaults to ‘open’.
  • estimatedPrice (float) - the estimated price of the service
  • duration (int) - the estimated duration of the service, in seconds
  • recurring (boolean) - if true, a recurring service should be created; if false, a one-time service should be created. Currently should always be false. [REQUIRED]

createJobAttachments(attachmentsArray)

Creates a set of job attachments from the given array. Each array member should have the following properties:

  • jobId (int) - ID of the job to which the attachment should be added [REQUIRED]
  • attachmentUrl - the URL of the attachment [REQUIRED]

Returns an array of attachment objects.

Example destination rule

/* creates a job attachment if the ‘Interesting Job Image’ question is answered */
let jobAttachmentsToCreate = [];
if (SF.answers.Interesting_Job_Image && SF.answers.Interesting_Job_Image.value) {
jobAttachmentsToCreate.push({
attachmentUrl: SF.answers.Interesting_Job_Image.value,
jobId: SF.job.id
});
}
await SF.createJobAttachments(jobAttachmentsToCreate);

createAssetAttachments(attachmentsArray)

Creates a set of asset attachments from the given array. Each array member should have the following properties:

  • assetId (int) - ID of the asset to which the attachment should be added [REQUIRED]
  • attachmentUrl - the URL of the attachment [REQUIRED]

Returns an array of attachment objects.

Example destination rule

/* creates attachments on all assets that have the ‘Interesting Image’ question answered */
let assets = SF.answers.servicetrade_assets ? SF.answers.servicetrade_assets.values : [];

let assetAttachmentsToCreate = [];
for (let a of assets) {
const assetId = d.asset_id ? d.asset_id.value : null;
if (assetId && a.Interesting_Image && a.Interesting_Image.value) {
assetAttachmentsToCreate.push({
attachmentUrl: a.Interesting_Image.value,
assetId: assetId
});
}
}
await SF.createAssetAttachments(assetAttachmentsToCreate);

createContacts(contactsArray)

Creates a set of contacts from a given array. Each array member should have the following properties:

  • locationId (int) - ID of location to which contact should be added [REQUIRED, unless customerId is supplied]
  • customerId (int) - ID of customer to which contact should be added [REQUIRED, unless locationId is supplied]
  • firstName (string) - contact first name
  • lastName (string) - contact first name
  • email (string) - contact email
  • phone (string) - contact phone
  • mobile (string) - contact mobile phone
  • alternatePhone (string) - contact alternate phone
  • type (string) - contact type

createDeficiencies(deficienciesArray)

Creates a set of deficiencies from a given array. Each array member should have the following properties:

  • assetId (int) - ID of asset to which deficiency should be added [REQUIRED]
  • jobId (int) - ID of job on which deficiency is being reported [REQUIRED]
  • severity (enum, one of: ‘inoperable’, ‘deficient’, ‘suggested’) [REQUIRED]
  • description (string) [REQUIRED]
  • status (enum, one of: ‘new’, ‘verified’, ‘fixed’) [REQUIRED]
  • reportSource (enum, one of: ‘manual’, ‘mobile’) [REQUIRED]
  • proposedFix (string) - the proposed fix for the deficiency
  • attachments - an array of attachment objects, each containing:

image (string) - the attachment URL [REQUIRED]

description (string) - the description of the attachment

Returns an array of created deficiency objects.

For each deficiency, this method will construct and execute an API call like:

let deficiencyPayload = {
assetId: assetId,
severity: severity,
description: description,
status: status,
reportSource: reportSource,
jobId: jobId,
attachments: [
{image: image1Url},
{image: image2Url, description: ‘broken whizbang’},
...
]
};
servicetrade.post('/deficiency', deficiencyPayload);

Example Destination Rule

/* creates deficiencies for each asset that has a Visual or Functional test failure */

let assets = SF.answers.servicetrade_assets ? SF.answers.servicetrade_assets.values : [];
/* create new assets */
for (asset of assets) {
const assetId = asset.asset_id ? asset.asset_id.value : null;
if (!assetId) {
const assetPayload = {
locationId: SF.job.location.id,
type: 'hvac_unit',
properties: {
barcode: asset.properties_barcode ? asset.properties_barcode.value : null,
area_serviced: asset.properties_area_serviced ? asset.properties_area_serviced.value : null
}
};
const newAsset = await SF.createAssets([assetPayload]);
/* assign the newly created asset ID to this asset record */
asset.asset_id = {value: newAsset[0].id};
}
}
const deficientAssets = assets.filter(v => {
return (v.Visual && v.Visual.value == 'Fail') || (v.Functional && v.Functional.value == 'Fail');
});
let deficienciesToCreate = [];
for (let d of deficientAssets) {
let description, deficiency, severity;
const assetId = d.asset_id ? d.asset_id.value : null;

const failFunctional = d.Functional && d.Functional.value == 'Fail';
const failVisual = d.Visual && d.Visual.value == 'Fail';
if (failVisual && !failFunctional) {
description = 'Visual test failure';
severity = 'deficient';
} else if (!failVisual && failFunctional) {
description = 'Functional test failure';
severity = 'inoperable';
} else {
description = 'Visual and functional test failure';
severity = 'inoperable';
}
let deficiencyPayload = {
assetId: assetId,
severity: severity,
description: description,
status: 'verified',
reportSource: 'mobile',
jobId: SF.job.id,
attachments: []
};
if (d.Visual_Failure_Image && d.Visual_Failure_Image.value) {
deficiencyPayload.attachments.push(d.Visual_Failure_Image.value);
}
if (d.Functional_Failure_Image && d.Functional_Failure_Image.value) {
deficiencyPayload.attachments.push(d.Functional_Failure_Image.value);
}
deficienciesToCreate.push(deficiencyPayload);
}
await SF.createDeficiencies(deficienciesToCreate);

updateDeficiencies(deficienciesArray)

Updates a set of deficiencies from a given array. Each array member should have the following properties:

  • deficiencyId (int) - ID of deficiency being updated [REQUIRED]
  • jobId (int) - ID of job on which deficiency is being updated
  • severity (enum, one of: ‘inoperable’, ‘deficient’, ‘suggested’)
  • description (string) - description of the deficiency
  • status (enum, one of: ‘new’, ‘verified’, ‘fixed’)
  • reportSource (enum, one of: ‘manual’, ‘mobile’)
  • proposedFix (string) - the proposed fix for the deficiency
  • attachments - an array of attachment objects, each containing:

Returns an array of created deficiency objects.

For each deficiency, this method will construct and execute an API call like:

let deficiencyPayload = {
assetId: assetId,
severity: severity,
description: description,
status: status,
reportSource: reportSource,
jobId: jobId,
proposedFix: proposedFix
};

servicetrade.put('/deficiency/' + deficiencyId, deficiencyPayload);

// ... with a followon request to add attachments to the deficiency if any were provided

Questions?

All support requests for ServiceForms should be emailed to serviceforms@servicetrade.com.

Did this answer your question?