# Assignment of Sample Next Steps Based On a UDF

In the default configuration of Clarity LIMS, at the end of every step, the user is required to choose where the samples will go next - i.e. the 'next step'.

If samples in the lab follow a logical flow based on business logic, this is an unnecessary manual task. This example shows how to automate this next step selection, to reduce error and user interaction.

This example uses the **Automatically Assign Next Protocol Step (Example)** step, in the **Automation Examples (API Cookbook)** protocol. The examples shoes how to:

* Automate the selection of a sample's **Next Steps**, as displayed on the **Assign Next Steps** screen of this step.
* Use the **Pooling** sample UDF / custom field to determine which next step each sample is assigned.

### Solution <a href="#solution" id="solution"></a>

#### Step Configuration

The **Automatically Assign Next Protocol Step (Example)** step has two permitted **Next Steps**:

* Confirmation of Low-plexity Pooling (Example)
* Automated Workflow Assignment (Example)

Depending on the value of a sample's **Pooling** UDF / custom field, the sample's **Next Step** will default to one of the permitted next steps:

* If the value of the **Pooling** UDF / custom field is any case combination of **No** or **None**, the sample's next step will default to **Automated Workflow Assignment (Example)**.
* Otherwise, the sample's next step will default to **Confirmation of Low-plexity Pooling (Example)**.\
  \
  ![Assignment\_of\_samples\_based\_on\_UDF.png](https://genologics.zendesk.com/attachments/token/Lhczr7f8TGXlpUKDhZe6370Yo/?name=Assignment_of_samples_based_on_UDF.png)\
  \&#xNAN;***Next step configuration (LIMS v4.x shown)***

**Automation** is configured as follows:

* **Behavior:** Automatically initiated
* **Stage of Step:** On **Record Details** screen
* **Timing:** When screen is exited

#### Parameters

The script takes three basic parameters:

<table data-header-hidden><thead><tr><th width="99"></th><th></th><th></th></tr></thead><tbody><tr><td>-u</td><td>The username of the API user (Required)</td><td>The {username} token</td></tr><tr><td>-p</td><td>The password of the API user (Required)</td><td>The {password} token</td></tr><tr><td>-i</td><td>The URI of the step that launches the script (Required)</td><td>The {stepURI:v2:http} token, in the form:<br><em>http://&#x3C;Hostname>/api/v2/steps/&#x3C;ProtocolStepLimsid></em></td></tr></tbody></table>

An example command line is shown below.

(Note: The location of groovy on your server may be different from the one shown in this example. If this is the case, modify the script accordingly.)

{% code overflow="wrap" %}

```
bash -c "/opt/gls/groovy/current/bin/groovy -cp /opt/groovy/lib /opt/gls/clarity/customextensions/NextStepAutomation.groovy -u {username} -p {password} -i {stepURI:v2:http}" 
```

{% endcode %}

### User Interaction <a href="#interaction" id="interaction"></a>

Assuming samples have been placed in the protocol and are ready to be processed, the user proceeds as normal:

1. Upon reaching the transition from the **Record Details** screen to the **Assign Next Steps** screen, the script is run. A message box alerts the user that a custom script is in progress.
2. Upon completion of the script, a custom success message is displayed.
3. Once the success message is closed and the screen has transitioned, the default next steps display for the samples.

### About the Code <a href="#code" id="code"></a>

Once the script has processed the input and ensured that all the required information is available, we can start to process the samples to determine their next steps.

1. First, we retrieve the next actions list:\\

   ```
   // Retrieve the current protocol step
   String nextActionsURI = stepURI + '/actions'
   Node nextActionsList = GLSRestApiUtils.httpGET(nextActionsURI, username, password)
   String currentProtocolStepURI = nextActionsList.'configuration'[0].@uri
   Node currentProtocolStep = GLSRestApiUtils.httpGET(currentProtocolStepURI, username, password)
   ```
2. This endpoint contains a list of the step's output analytes, and a link to its parent step configuration. In this case, we want to retrieve the step configuration so that we can collect the URIs of the expected next steps.

   ```
   // Determine the uris of the possible next steps
   currentProtocolStep.'transitions'.'transition'.each {
       if(NEXT_STEPS.containsKey(it.@name)) {
           NEXT_STEPS[it.@name] = it.@'next-step-uri'
       }
   }
   ```
3. Once we have retrieved the step configuration, we iterate over its possible next steps, gathering their URIs and storing them by name in a **Map**.
4. Once we have collected the URIs of our destination steps, we can start analyzing each sample to determine what its default should be.
   * For each possible 'next-action', we retrieve the target artifact, which then enables us to retrieve that artifact's parent sample.
   * We then retrieve the value of the sample's **Pooling** UDF / custom field , if it exists. If it doesn't exist, a default value is given.\\

     ```
     // For each output analyte, set its corresponding next step according to the value of the UDF 'Pooling'
     nextActionsList.'next-actions'.'next-action'.each {
         Node artifact = GLSRestApiUtils.httpGET(it.@'artifact-uri', username, password)
         Node sample = GLSRestApiUtils.httpGET(artifact.'sample'[0].@uri, username, password)
         String poolingValue = sample.'udf:field'.find { UDF_NAME == it.@name } ? sample.'udf:field'.find { UDF_NAME == it.@name }.value()[0] : 'Default'
      
         // If Pooling is a variation of No or None, set to workflowAssignment, otherwise set to pooling step
         if(!NO_VALUES.contains(poolingValue.toLowerCase())) {
                 it.@action = NEXT_STEP_ACTION
                 it.@'step-uri' = NEXT_STEPS[POOLING_STEP]
                 poolingSamples++
         } else {
                 it.@action = NEXT_STEP_ACTION
                 it.@'step-uri' = NEXT_STEPS[WORKFLOW_STEP]
                 workflowAssignmentSamples++
         }
     }
     ```
   * To set the next step, we set the **step-uri** attribute of the node to the URI of the expected destination step.
     * We also increment counters, so that we can report to the user what actions were taken on the given samples.
     * Once this is done, we perform an **httpPUT** on the action list, adding the changes to the API and allowing our defaults to be set.
   * Finally, we define the successful output message to the user. This allows the user to check the results.

     ```
     // Update the next steps in the API
     GLSRestApiUtils.httpPUT(nextActionsList, nextActionsURI, username, password)
      
     // Define the success message to the user
     outputMessage = "Script has completed successfully.${LINE_TERMINATOR}" +
                 "Next steps for ${poolingSamples + workflowAssignmentSamples} samples have been set:${LINE_TERMINATOR}" +
                 "${poolingSamples} samples set to '${POOLING_STEP}'.${LINE_TERMINATOR}" +
                 "${workflowAssignmentSamples} samples set to '${WORKFLOW_STEP}'."
     ```

### Assumptions and Notes <a href="#prereqs" id="prereqs"></a>

* You are running a version of Groovy that is supported by Clarity LIMS, as documented in the Clarity LIMS Technical Requirements.
* The attached Groovy file is placed on the LIMS server, in the folder **/opt/gls/clarity/customextensions**
* **GLSRestApiUtils.groovy** is placed in your Groovy lib folder.
* A single-line text sample UDF named **Pooling** has been created.
* The example code is provided for illustrative purposes only. It does not contain sufficient exception handling for use 'as is' in a production environment.

### Attachments

NextStepAutomation.groovy:

{% file src="<https://2084401275-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfjuebS41N49G1Eh55hP7%2Fuploads%2Fgit-blob-5abd96a9565b99dd3337b5900dced4decb0df16d%2FNextStepAutomation.groovy?alt=media&token=e8c212b7-eb5a-4a4e-840a-f8bfb55682ae>" %}
