# ServiceNow Work Order Integration

### 1. Introduction

This guide outlines the process for integrating ServiceNow, an external work order management system, with the AirHub® Portal. The goal is to establish a seamless two-way flow of work order data: creating work orders in the Portal from ServiceNow and reflecting Portal status updates back into ServiceNow.

### 2. Overview of the Integration Flow

The integration involves a two-way communication setup:

* **Inbound Flow (ServiceNow to AirHub® Portal - Work Order Creation):**
  1. A record is created or updated in ServiceNow.
  2. This triggers a **ServiceNow Business Rule** to send an HTTP request containing work order data.
  3. A **Power Automate Flow (Inbound)** receives this request, transforms the ServiceNow data format into Airspace Link's standard work order schema.
  4. The Power Automate flow calls the Airspace Link API to create or update the work order in the AirHub® Portal.
  5. The work order appears in the AirHub® Portal, mapped to the correct organization.
* **Outbound Flow (AirHub® Portal to ServiceNow - Status Updates):**
  1. An update is made to a work order within the AirHub® Portal (e.g., status, notes, deliverable URL).
  2. This triggers an internal AirHub® Portal process that calls a **Power Automate Flow (Outbound)**.
  3. This Power Automate Flow transforms Airspace Link's update schema into ServiceNow's expected format.
  4. The Power Automate flow publishes the update to a designated **ServiceNow Scripted REST API endpoint**.
  5. The original work order record in ServiceNow is updated.

### 3. Pre-Integration Steps & Information Gathering (From Customer)

Before configuring the integration, essential information and access are required from the customer:

#### 3.1. Understand the Customer's ServiceNow Configuration

* Familiarize yourself with their specific ServiceNow instance and how they use it for work orders.
* Understand their existing intake forms and the fields they use.

#### 3.2. Gather Key Information & Access from the Customer

* **ServiceNow Instance URL:** The base URL of their ServiceNow instance.
* **User Credentials:** A dedicated user account within their ServiceNow instance for integration purposes.
  * **Required Permissions:** This user needs permissions to:
    * Create **Business Rules**.
    * Create **Scripted REST APIs**.
    * Update tables&#x20;
* **Field Mapping Details:** For **ALL** fields in their intake form that need to be integrated with AirHub® Portal:
  * Exact field names (as they appear in ServiceNow).
  * All possible values for each field, including their **underlying numeric or exact database values** (not just the displayed text labels).
    * *Example: "Pending" might have an underlying value of "-5". These often require direct API calls or specialized ServiceNow views to determine.*
    * *Note: This often requires experimentation (sending API requests and observing transformations) or direct access to their database schema views within ServiceNow.*
* **Custom Field Behavior:** Identify any custom fields that behave unusually (e.g., `work_notes` field requires specific update methods via `PATCH` rather than direct assignment).
* **Location Data:** Understand how they currently define operation locations (e.g., text addresses, no geometry).

### 4. Airspace Link Portal Configuration (By Airspace Link)

#### 4.1. Create Power Automate Flows&#x20;

* **Draft Inbound Power Automate Flow:** Create a Power Automate flow designed to receive HTTP requests from the customer's ServiceNow Business Rule. This flow will generate a unique URL.
* **Draft Outbound Power Automate Flow:** Create a Power Automate flow designed to receive updates from the Airspace Link Portal and publish them back to ServiceNow.
* **Obtain Outbound URL:** For the *outbound* flow (Airspace Link to ServiceNow), note the unique HTTP request URL generated by Power Automate. This will be used in Airspace Link's `org.json` configuration.

#### 4.2. Update Airspace Link Configuration File

* Navigate to the `org.json` configuration file in the Airspace Link GitHub repository (specific location to be provided by engineering).
* For each environment (e.g., Development, Staging, Production), add a new entry for the customer's organization.
* **Required Data for Each Organization Entry:**
  * `uniqueId`: A unique, randomly generated ID (can be generated by Airspace Link).
  * `org_name`: The exact organization name as defined in Auth0.
  * `org_id`: The unique organization identifier from Auth0.
  * `outbound_url`: The HTTP request URL generated from the *outbound* Power Automate flow (see Section 4.1).

### 5. ServiceNow System-Specific Configuration (By Airspace Link)

#### 5.1. Business Rule (Inbound Trigger - ServiceNow to AirHub® Portal)

* **Objective:** To trigger a send of ServiceNow work order data to Airspace Link's inbound Power Automate flow.
* **Action:** Configure a new **Business Rule** within ServiceNow.
  * **Table:** Tie this rule to the specific ServiceNow table where work orders are managed.
    * Ensure the `Active` and `Advanced` fields are both checked
  * **Conditions:** Set conditions for when the rule fires (e.g., on `insert`, `update`, or `delete` of a record).
  * **Script:** In the `Advanced` tab, implement a custom script within the Business Rule to:

    * Extract relevant fields from the ServiceNow record.
    * Construct an HTTP POST request.
    * Send this request to the unique URL of the **inbound Power Automate flow**.

    ```
    // Example script

    (function executeRule(current, previous /*null when async*/) {
        var restMessage = new sn_ws.RESTMessageV2(); 
        restMessage.setEndpoint('https://prod-72.westus.logic.azure.com:443/workflows/uniquePowerAutomateUrlAbc123'); 
        restMessage.setHttpMethod('POST'); 
        
        // Send the current work order as JSON 
        var requestBody = { 
            taskNumber: current.number.toString(),
            priority: current.priority.toString(),
            state: current.state.toString(),
            shortDescription: current.short_description.toString(),
            description: current.description.toString(),
            sys_id: current.sys_id.toString(), 
    		dueDate: current.due_date.toString(),
            link: current.getLink(),
    		location: current.location.toString(),
    		locationDescription: current.u_location_description.toString()
        }; 
        
        restMessage.setRequestBody(JSON.stringify(requestBody)); 
    	restMessage.setRequestHeader('Content-Type', 'application/json');
        var response = restMessage.execute();
    })(current, previous);
    ```

#### 5.2. Power Automate Flow (Inbound - Field Transformation)

* **Objective:** To receive ServiceNow data, transform it, and send it to the Airspace Link API.
* **Action:** Configure the Power Automate flow:
  * **Trigger:** Set to "When an HTTP request is received".
  * **Field Definition:** Define the expected fields from the ServiceNow request.
  * **Data Mapping:** Implement logic to transform ServiceNow's field names and values into Airspace Link's standardized work order schema (e.g., mapping `state` from "-5" to "Pending").
  * **API Call:** Add an action to make an HTTP POST or PUT request to the Airspace Link API to create or update the work order.
    * **ASL API URL**: `https://airhub-api-dev.airspacelink.com/v1/workorder/webhook/{uuid}` where uuid is the unique organization id contained in the [org.json configuration file](https://github.com/airspace-link-inc/astm-scd/blob/main/bento/workorder-integration/resources/dev/org.json)

#### 5.3. Scripted REST API (Outbound Reception - AirHub® Portal to ServiceNow)

* **Objective:** To receive work order updates from AirHub® Portal and apply them to ServiceNow records.
* **Action:** Create a **Scripted REST API** in ServiceNow.
  * **Endpoint:** Define a unique, external endpoint that can accept calls from outside ServiceNow.
  * **Method:** Configure the method (e.g., `PATCH` for updates).
  * **Resource path:** Note the resource path generated. This will be used by the **outbound Power Automate flow** to publish updates to ServiceNo&#x77;**.**&#x20;
  * **Script:** Implement a script within this API to:

    * Receive the update request from the **outbound Power Automate flow**.
    * Identify the specific ServiceNow record to update (e.g., using a unique ID passed in the request).
    * Update the relevant fields (e.g., status, notes, deliverable URL) in that record.
    * *Handle any custom field behaviors as identified in Section 3.2.*

    ```
    (function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
        // Extract the data from the request body
        var requestBody = request.body.data;

        // Extract the unique identifier of the record to update from the request body
        var idNumber = requestBody.id;

        // Create a new GlideRecord object for the 'sc_task' table
        var gr = new GlideRecord('sc_task'); 

        // Attempt to retrieve the record with the specified 'number' (idNumber)
        if (gr.get('number', idNumber)) { 
            // Iterate over each field in the request body
            for (var field in requestBody) {
                // Check if the field is a direct property of requestBody
                if (requestBody.hasOwnProperty(field)) {
                    // Set the value of the field in the GlideRecord object
                    gr.setValue(field, requestBody[field]);

                    // Handle special/unique fields separately
                    if (field == 'work_notes') {
                        // Set the 'work_notes' field specifically
                        gr['work_notes'] = requestBody[field];
                    }
                }
            }

            // Disable workflow processing for this update to prevent it from firing other triggers
            gr.setWorkflow(false); 

            // Update the record in the database
            gr.update();

            // Set the response status to 200 (OK) and return a success message
            response.setStatus(200);
            response.setBody({ message: 'Record updated successfully' });
        } else {
            // If the record is not found, set the response status to 404 (Not Found)
            response.setStatus(404);
            response.setBody({ error: 'Record not found' });
        }

    })(request, response);
    ```

### 6. Testing & Validation

Thorough testing is crucial to ensure the two-way integration works as expected.

* **Test Inbound Flow:** Create/update a work order in ServiceNow and verify it appears correctly in the AirHub® Portal with all mapped fields.
* **Test Outbound Flow:** Update a work order's status, notes, or deliverable URL in the AirHub® Portal and verify these changes are reflected accurately in the original ServiceNow record.

### 7. Important Considerations & Best Practices

* **Field Mapping Complexity:** Be prepared for detailed conversations with customers about their field definitions and values, especially for custom fields that may require specific handling.
* **Power Automate Flow Ownership:** A clear decision is needed on whether the customer or Airspace Link will own and manage these Power Automate flows. This impacts necessary access and instruction levels.
* **Documentation:** Capture detailed documentation as you go for each integration, particularly for unique customer configurations, to build repeatable processes.
