NAV Navbar
ruby
  • Introduction
  • Manipulating Subjects
  • Workflows and States
  • Messages
  • User Defined Fields (UDFs)
  • Creating Custom Views and Forms
  • Sending Emails
  • Errors
  • API
  • Guides
  • Modelling your data with Limfinity
  • Creating workflows
  • Introduction

    Limfinity scripting enables the user to expand out-of-the-box Limfinity framework functionality. Below are a couple examples that can be done with scripting.

    Getting Started

    Any UI element in Limfinity can be configured with a script which will run before or after the UI element is clicked. The Ruby language is used to create scripts in Limfinity. Examples of this include:

    You can view all configured scripts in Limfinity by going to "Settings and Preferences" --> More Settings --> All Scripts

    What is a User-Defined Field (UDF)?

    User-Defined Fields (UDFs) make up the subjects in Limfinity. Each UDF corresponds to a subject property. There are many types of UDFs, each with its own corresponding value types. For example, a “Number” type UDF only supports the entering of numerical values, whereas a “Date” type UDF only supports date format values. UDFs are often set using scripts.

    Values

    Values in Limfinity are defined as the generic objects which are to be manipulated. Values can be user-defined fields, standard fields, names, and IDs.

    What is a Subject?

    A subject is a Limfinity object with defined fields and values. A subject can have any number of fields, including collections of other subjects. Subjects are the core objects in Limfinity which are manipulated and handled to store data. Subjects can be of any type which has been defined in the Limfinity system, and there is no limit to the number of subjects which can be created. Subjects store data in standard and user-defined fields, and progress through respective workflows.

    Using subjects in scripting

    “Subj” is a Limfinity term which refers to the currently opened subject. For example, when working with a sample subject record, “subj” in a script in that record’s window will refer to that subject. Any get_value() calls will refer to the data within that subject.

    Accessing Entered Values in a Form

    # Populate the subject with values from a form, unless the value in the form is blank
    params.each_pair{|udf, value|
      if value.present?
        subj.set_value(udf, value)
      else
        subj.remove_prop(udf)
      end
    }
    

    It is sometimes necessary to get the value of a field object in a script for variable assignment or storage. When manipulating a subject in a script, the get_value() method is used. However if a script is being run without a subject object, for example when entering information into a form via a Quick Link, then the params[] call is used. The params[] call obtains the value which is entered into the form, respective to each field.

    Parameters

    # Using the params[:required] script will ensure that each UDF with a "true" parameter must have a value
    # before the form can be submitted.
    params[:required] = {
        'Chem Analyses' => true,
        'Chemistry Package' => true
    }
    

    Parameters are accessed in a similar way as fields with already set values. The standard syntax for obtaining a parameter’s information is params[‘FIELD NAME’]. This call is very useful when creating a subject. The params[] call may be used within a set_value() method call, where the parameter may be the value to set.

    Exception Handling

    # The raise method is used for exception handling, and is also good for debugging
    # Here we raise the value of the "Sample Type" UDF of the opened subject to see its value in a new window
    raise subj.get_value('Sample Type')
    
    # Here we raise an error message if the value of the "PH Level" UDF is higher than 7
    if subj.get_value('PH Level') >= 7
        raise "PH level is too high"
    end
    

    Limfinity supports the Ruby “Raise” method, which is used for handling exceptions. When an exception (error) needs to be handled, the raise method is an excellent tool. When an exception is handled using the raise method, the script in Limfinity will cease running, and as a result no actions will have been performed.

    The raise method can be used for exception handling, and for logic and value checking. In this example, an error message is thrown if the value of the subject’s “PH Level” is higher than 7.

    Debugging

    The inspect method can be called on a subject to provide output of a specified value inside a raise statement. This is equivalent to calling to_json on a Limfinity object. The raise method can be used to break out of a script and display a message.

    To troubleshoot an error thrown by Limfinity:

    Manipulating Subjects

    Get Value

    # In this example, a variable ‘age’ is set to the value of the subject’s “Age” user-defined field.
     age = subj.get_value('Age')
    
    # This subject is a "Testing Run". A testing run can have a sample, which can have its own information
    #  This call will obtain the value of the dilution of the sample within the testing run
    #It is possible to “chain” get_value() method calls for downstream objects. In this example, the value of a
    #testing run’s sample’s dilution is obtained. There is no limit to the number of get_value() chains that may
    #be called.
    dilution = subj.get_value('Sample').get_value('Dilution')
    
    # The object 'Samples' is a collection of sample subjects, therefore it is stored in an array.
    # A get_value() method call can be used to obtain teh collection of sample subjects.
    samples = subj.get_value('Samples')
    
    #For example, the destroy method will destroy the first sample (index) in the samples array,
    # As designated by the [0]. Note that array indeces start at 0.
    samples.[0].destroy
    
    #Loops can also be used to perform actions on all elements in the array.
    samples.each do |example|
      example.destroy
    end
    

    Returns a value of a property. The get_value() method is used for obtaining a value of a subject’s or several subjects’ user-defined fields. This method gets the value of the defined parameter, and stores it in any variable to which it is assigned.

    Defining Subject - “Subj”

    “Subj” is a Limfinity term which refers to the currently opened subject. For example, when working with a sample subject record, “subj” in a script in that record’s window will refer to that subject. Any get_value() calls will refer to the data within that subject.

    Parameters

    Parameter Description
    property The value of the property to retrieve

    It is possible to “chain” get_value() method calls for downstream objects. There is no limit to the number of get_value() chains that may be called.

    Arrays are collections of data, therefore the get_value() method call can be used to obtain the value of the collection.

    Note that in order to perform any action on an element in the array, a loop must be used for a single index that must be defined

    Set Value

    # Example: Setting a single value
    # Set_value takes two parameters. The first parameter is the value (Request Method), and the second is the intended value (Metagenomics).
    # Here we set the request method for the subject to Metagenomics.
      subj.set_value('Request Method', 'Metagenomics')
    
    # Chaining get_value() to set_value()
    # In this example, a subject has a reference subject called “First Analysis”. The “First Analysis” subject has a subject called “First Sample”.
    # With this chained call, the “First Sample” subject is having its “Sample Name” UDF assigned the value of “Example”, even though that subject is not currently opened on the screen.
    # set_value() can be chained together after a get_value()
    # Here we get the field "First Sample" from the field of a referenced subject "First Analysis" of the opened subject,
    # and set the value of that first sample's UDF "Sample Name" to "Example".
    subj.get_value('First Analysis').get_value('First Sample').set_value("Sample Name", "Example")
    
    # Looping set_value()
    # Loops are very useful when it is necessary to set the value of a field for several subjects
    # Here we get the array of analyses of this subject, loop through each one, and set the UDF value "Checked" to "Yes"
    subj.get_value('Analyses').each do |analysis|
      analysis.set_value('Checked?', 'Yes')
    end
    

    The set_value() method is used for setting the value of a subject’s or several subjects’ user-defined fields. The method accepts two parameters, the first of which is the field to be set, and the second of which is the intended value.

    Parameters

    Parameter Description
    property The intended property to be set
    value The intended value for the property

    Removing Values

    # This example has the user select a Test Panel that will have all associated Lab Tests removed
    panel = params['Select Panel to Clear Tests From']
    panel.remove_prop('Lab Tests')
    

    The remove_prop() method is used to clear the contents of user defined fields within a subject. The remove_prop() method is executed on the subject that calls the method. Note that the UDF is not permanently removed from the subject; remove_prop() method clears the value currently stored in the UDF for calling subject.

    Parameters

    Parameter Description
    property The value of the property to clear

    Naming Subjects

    # Example: Overriding the Name of a Subject
    
    # To set the name of a subject, an assignment operation can be used. Note that subject names must always be unique.
    # Here we overwrite the name of the subject by appending the current date and time to it.
    # Using the current date and time is a good way to ensure that the name of the subject remains unique.
    subj.name = (subj.name + Time.now.to_s)
    
    #  Example: get_next_name_number
    
    # Using the get_next_name_number is another way to ensure that a subject’s name remains unique. This method can be used when creating a subject or reassigning its name.
    # Here we use the get_next_name_number method to ensure the subject's name is unique
    "Sample " + '-' + ("%05d"% subject_type.get_next_name_number)
    

    Subjects can be named in a variety of ways in Limfinity. For example, names can be generated via the subject type’s extension, or they can be set manually during a subject edit, or they may be modified using a simple assignment operation.

    params[:display_field] = {
      'Submission' => 'Submission Name'
    }
    

    Using params[:display_field] in Before Script

    User can choose any ‘Text Field’ UDF as a display option for linked subject(s) instead of the system generated ‘Name’ field.

    Creating Subjects

    # Here we create a subject, and within a loop set a few of its UDF values
    # Note that the UDF values are being set to the values which have been entered into the form by using the params[] objects
    subject = create_subject('Job') do |jb|
      jb.set_value('Client', params['Client'])
      jb.set_value('# of Samples', params['# of Samples'])
    end
    
    # Here we call the create_subject method and create a subject of type "QC Sample"
    # Using the open_subject() method call, the created subject will be opened.
    
    subject = create_subject('QC Sample') do |qc|
      qc.name = params['Name']
      qc.set_value('Lot #', params['Lot #'])
    end
    
    open_subject(subject)
    

    To create subjects via scripts in Limfinity, the create_subject() method is called. The create_subject() method is often called using a loop, so as to create multiple subjects, or to assign values to the subject which is being created.

    It is often the intent to create a subject and immediately begin working on it, however the create_subject() method call only creates the subject. In order to open the subject to immediately view it and work with it after it has been created, the open_subject() method call is used.

    Parameters

    Parameter Description
    subject_type The subject type of which the subject is to be created.

    Deleting Subjects

    # Here we delete each sample associated with the subject
    
    subj.get_value(samples).each do |sample|
      sample.destroy
    end
    
    def before_delete_action
      false
    end
    

    To delete subjects in Limfinity, the destroy() method is used. Calling the destroy() method will delete the subject from the database. The associated information and user-defined field data will be deleted as well.

    Prevent Deleted Subjects

    Add a method to Subject Type Subject Extension to prevent a user deleting any related subject/s by any means.

    Copying Properties from Another Subject

    # Here we create a new family, and copy the properties of it from an existing family (subject)
    familyname = params['Family']
    
    patient = create_subject('Patient') do |p|
        p.set_value('Family', familyname)
        p.set_value('UDP Inquiry', subj)
        p.copy_properties_from(subj)
    end
    

    To copy properties from one subject to another, the copy_properties_from() method is used. This method is useful for duplicating subjects, and creating new subjects with existing data.

    aside class="notice"> Copying properties works simply by taking a subject (user-defined field) and duplicating that data into another subject.

    Setting Permissions

    ug = UserGroup.find_by_name('Users')
    sub = params['Project']
    subj.set_value('Project', sub)
    # Acl::NOACCESS, Acl::READONLY, ACL::READWRITE
    Acl.set_permissions(sub, ug, Acl::READWRITE)
    

    The set_permission method is used to set a permission flag on an object for a user group. The following parameter definitions for the parameters are explained below:

    The syntax for the Acl.set_permission method is as follows:

    Acl.set_permission(subject, user_group, NOACCESS/READONLY/READWRITE)

    The following After Script is used to give READWRITE permission to subject type- subject ‘Project’ for user group ‘Users’. The subject type ‘Project’ is set as ‘READONLY’ for user group ‘Users’

    Removing Permissions

    ug = UserGroup.find_by_name('Users')
    sub = params['Project']
    subj.set_value('Project', sub)
    # Acl::NOACCESS, Acl::READONLY, ACL::READWRITE
    Acl.remove_permission(sub, ug)
    

    The remove_permission method is used to remove a permission flag on an object for a user group. The syntax for the Acl.remove_permission method is as follows:

    Acl.remove_permission(subject, user_group)

    Workflows and States

    Workflows and states are the core of the Limfinity platform. Workflows dictate what types of objects can be manipulated, when they can be manipulated, and how. Workflows are the main engine in Limfinity and explain the individual processes which each object goes through.

    Starting Workflows

    # The start_workflow() method is used to start the workflow for a newly created subject
    # param1 - Name of the workflow as defined in the system
    # param2 - Subject for which the workflow should be started
    
    patient = create_subject('Patient') do |p|
        p.set_value('Family', params['Family'])
    end
    
    start_workflow('Patient Workflow', patient)
    

    When a subject is created, it needs to be placed into a workflow. The start_workflow() method is called to perform this. The start_workflow() method takes two parameters: the first parameter is the name of the workflow, and the second parameter is the subject for which the workflow should be started.

    There are two parameters required for the start_workflow() method:

    Property Description
    Workflow Name of the workflow as defined in the system
    Subject Subject for which the workflow should be started

    Advancing Workflows

    # Iterate over a set of subjects and create a new subject with the same properties
    # Place the subject into a 'Batched' state in the `Result` workflow
    spikes.each do |spike|
        new_result = create_subject('Result') do |rz|
          rz.copy_properties_from(spike)
          rz.set_value('Result Type', 'SAMPLE SPIKE')
        end
        advance_workflow('Result', 'Batched', new_result)
    end
    
    

    When a workflow has been started, or when it is in progress, it may be necessary to set a subject or list of subjects to a specific state. This can be done in any after script or run script, and so it can be performed in tools, workflow transitions, and even quick links.

    There are three parameters for the advance_workflow() method:

    Property Description
    Workflow The name of the Workflow in Limfinity
    Workflow State The name of the state to which the subject should be advanced, within the workflow
    Subject The subject object/loop index which is to be advanced.

    Acquiring All Subject States

    # Here we check to see if the subject has been in more than 5 states
    # If the subject has been in more than 5 states, an error is raised
    
    states_array = subj.states
    
    if states_array.count > 5
        raise "This subject has been in too many states"
    end
    

    If it is ever necessary to acquire a list of the states that a subject has been in during its lifetime, the states method may be used. A simple subj.states call may be used on the current subject, and an array of the subject’s states will be returned. This method is useful for quality control, but may also be used for checking if a subject has been in a specific state by using additional scripting.

    Determining the Current State of a Subject

    # Here we use the current_states method to check if the subject is in a specific state
    if subject.current_states = "Pending Approval"
        raise "This subject is currently in the 'Pending Approval' state"
    end
    
    # Here we advance the subject through a workflow, if its array of states includes 'HOLD'
    note = params['Employee Notes']
    subj.set_value('Employee Notes', note) if note.present?
    samples = subj.get_value('Samples')
    samples.each do |sample|
        advance_workflow('Sample', 'Received', sample)
    end
    advance_workflow('Sample Prep', 'MICRO', subj) if subj.current_states.map(&:name).include?('HOLD')
    

    It is often necessary to determine the current state of a subject. In order to successfully obtain the current state of an object, the current_states method is used. This method may be used in a check or in conjunction with an array index.

    Messages

    There are two different types of messages, which can be displayed via scripts in Limfinity: messages and alerts. Messages are displayed in confirmation dialogs, which the user must interact with, and alerts are displayed in a dropdown message for a short amount of time.

    Showing Messages

    #  Example: Showing Messages
    #Here we use the show_message() method to provide the user with a simple output message
    show_message("All samples have been selected for analyses. Please click 'OK' to proceed.")
    
    #  Example: Showing Alerts
    # Here we provide the user with a simple alert message, which they do not need to acknowledge
    show_alert("You are now in the next workflow state")
    

    Messages with confirmation dialogs are shown using the show_message() in After Script tab. The user will be required to click a confirmation “OK” button to acknowledge that they have seen the message. show_message() dialogs are shown after all other code has been executed.

    Text Messages from Input Forms

    params[:tab_name] = 'Samples'
    params[:subject_type] = 'Sample'
    params[:query] = search_query do |qb|
        qb.and(
          qb.state('Results Entry')
        )
    end
    params[:hint_msg] = '<p style="color:red">List of Samples.</p>'
    params[:tb_items] = [
       {xtype: 'box', html: ''<span style =\'color:darkgreen\'>Result Entry State</span>'}
    ]
    
    # Here we use a tool message to inform the user. THis message will be displayed in the tool itself
    params[:tool _message] = "Prior to performing this action, ensure that all other actions are complete"
    

    Text messages can be added to input forms by using the :tool_message parameter.

    Subject List with toolbar message

    User Defined Fields (UDFs)

    User-Defined Fields (UDFs) make up the subjects in Limfinity. There are many types of UDFs, each with its own corresponding value types. For example, a “Number” type UDF only supports the entering of numerical values, whereas a “Date” type UDF only supports date format values. UDFs are often set using scripts.

    Changing the way UDFs are displayed in grids

    if (value == null) {
    return  '<span style="color:blue;font-weight:bold;"> No </span>'
    } else return '<span style="color:red;font-weight:bold;"> '+val+' </span'
    

    Grid Renderer (JavaScript)

    Explorer Subject List View using Grid Renderer

    Making UDFs Required

    #Using the params[:required] script will ensure that each UDF with a 'true' parameter must have a value before the form can be submitted
    params[:required] = {
        'Chem Analyses' => true,
        'Chemistry Package' => true
    }
    

    It is often necessary to make sure a UDF has a corresponding value when a form is being completed. Furthermore, it may be necessary to ensure that a value has been entered prior to the form submission completion. Using the params[:required] in Before Script can accomplish this.

    Disabling UDFs in Forms

    # Here we disable the 'Submitter Name' UDF, as it should be a read-only UDF
    params[:disabled] = {
        'Submitter Name'=>true
    }
    

    UDFs can be disabled in forms by using the params[:disabled] parameter in Before Script. This parameter is used when specific UDFs in a form should be disabled, in order to enforce read-only access to the user.

    Skipping/Hiding UDFs in Forms

    # Here we skip the 'Submitter Name' UDF if it already has an entry
    if subj.get_value('Submitter Name').present?
        params[:skip_UDF] = {
          'Submitter Name' => true
        }
    end
    

    It is possible to skip or hide a UDF when editing a subject form, by using the params[:skip_UDF] parameter. This is a very useful tool when logic is involved when editing a subject.

    Creating Custom Views and Forms

    Custom views and forms may be created in Limfinity, in lieu of the default form formatting. By default, Limfinity will build a default form containing all the UDFs that were passed in as parameters to the tool. The parameter UDFs can be modified in before and after scripts (making fields required or disabled, adding input validation, etc). However, it is possible to completely override the default form look and feel by replacing it with your own custom view.

    Creating a simple form

    # Before script: Open a form when on or more sample records are selected in the grid. Display a dialog with storage fields
    raise "Please select at least one sample" unless subjects.length > 0
    
    params[:dialog_options] = {maximizable: true, resizable: true, layout: fit}
    params[:required] = {
    'Freezer'=>true,
    'Rack'=>true,
    'Shelf'=>true,
    'Date Stored'=>true
    
    # After script: Update each selected sample with storage information from the form and update their status. Display alert to the user when operation is completed.
    subjects.each do |s|
      s.set_value('Freezer', params['Freezer'])
      s.set_value('Rack', params['Rack'])
      s.set_value('Shelf', params['Shelf'])
      s.set_value('Box', params['Box'])
      s.set_value('Slot', params['Slot'])
      s.set_value('Date Stored', params['Date Stored'])
    
      advance_workflow('Sample', 'Stored', s)
    end
    
    show_alert("#{subjects.length} Samples successfully stored to #{params['Freezer'].name}" )
    
    1. Create a quick link or a workflow tool
    2. Enter UDF names into the Script Parameters field (these UDFs must already exist in Limfinity) Script Parameters
    3. Create a before script (if you would like to apply attributes to the UDFs), or perform validation.
    4. Create an after script with the funcionality that needs to happen after the user clicks on the tool (this can be creation of new subjects, updating data, or displaying alerts)

    In this example, we are using params[:dialog_options] = {maximizable: true, resizable: true, layout: ‘fit’} to create a resizable dialog.

    Store sample

    Creating a custom form

    extend ScriptRunner::UI
    params[:custom_fields] = encode_fields([item1, item2...])
    params[:submit_disabled_as_empty] = true
    

    In order to create custom forms and UIs, a few scripts must be used. The layout form the form can either be defined in the before script, or in a helper script (if the layout is very complicated). view. A before script and after script are necessary for the tool. Once these three scripts are written and in place, the custom form may be used.

    To create a custom form:

    1. Create a quick link or a workflow tool
    2. Right-click on the workflow tool and click on Before Script
    3. You must extend the ScriptRunner:UI class
    4. Create an array of items that you want to display as fields on the form, and encode them by using the encode_fields method
    5. You must set the value of params[:custom_fields] property to the value returned by the encode_fields
    6. If you wish to submit disabled fields as empty values, you can use the property params[:submit_disabled_as_empty]

    Custom form with a fieldset

    # This example creates a form with multiple fieldsets and rows containing UDFs
    extend ScriptRunner::UI
    params[:custom_fields] =  encode_fields([
      field_set(title:'2012-0846', items:[
        field_row([
          udf('Patient Name', subj)
        ]),
        field_row([
          udf('MRN_Number',subj)
        ]),
        field_row([
          udf('Consenting Protocol', subj, labelWidth:150)
        ]),
        field_row([
          udf'PSC Date', subj),
          udf('PSC Type', subj, flex:3)
        ]),
        field_row([
          udf('Principal Investigator', subj, labelWidth:150)
        ]),
        field_row([
          udf('Title', subj.get_value('Consenting Protocol'))
        ]),
        field_row([
        udf('Requesting Investigator', subj)
        ]),
        field_row([
          (udf'Surgery Date', subj),
          udf('Surgeon', subj),
          udf('Building ID', subj),
          udf('Room ID', subj)
        ]),
        field_row([
          udf('Preliminary Diagnosis', subj)
        ])
      ]),
      field_set(title:'Tissue Specific Information', items:[
        field_row([
          udf('Sample Type', subj)
        ]),
        field_row([
          udf'Organ/Sites', subj)
        ]),
        field_row([
          udf'Processing Details', subj)
        ])
      ]),
      field_set(title:'Special Instructions', items:[
        field_row([
          udf('Special Instructions', subj)
        ]),
      field_set(title:'Pickup Information', items:[
        field_row([
          udf('Pick Up Date/Time', subj)
        ]),
        field_row([
          udf('Contact for Pickup', subj)
        ])
      ])
    ])
    

    This example demonstrates how to create a form with multiple fieldsets and multiple rows. Each row is created by calling field_row and passing it one or more udfs.

    Form with multiple fieldsets

    Custom form with hide/show logic

    # Create a custom form with a radio button and a field set. Here we want to show the field set only when
    # the value of the 'Find Requsitions' radio button is 'Submitted'
    extend ScriptRunner::UI
    params[:custom_fields] = encode_fields([
        udf('Find Requisitions', nil, labelWidth:160, required:false),
        field_set(title:'Find By Properities', border:'1 0 0 0', items:[
            udf('External Source ID', nil, info:'This field can be used for the Sample Barcode Entry',
              allowCreate:false, labelWidth:160, anchor:'100%'),
            udf('Requisition', nil, labelWidth:160, allowCreate:false),
            udf('Patient', nil, labelWidth:160, allowCreate:false),
            udf('Requesting Physician', nil, labelWidth:160, allowCreate:false),
            udf('Collection Date', nil, labelWidth:160, anchor:'50%'),
          ],
          react: {
            shown_when: 'value == "Submitted"',
            only: 'Find Requisitions'
        })
      ])
    

    You can attach listeners to any field by using the react property. In this example, we will hide/show a fieldset based on a value of a radio button. In order to hide or show a component you must use the shown_when property, and pass it an expression which evaluates to true or false. The only property can specify a component that the field will listen to. If only is missing, the field will listen to changes on all fields on the form.

    Find Requisitions

    Populating form fields with values from other fields

    # In this example we first pick a Billing Facility, and then auto-populate the Billing Facility Address field with the
    # value of the facility's address stored in the database.
    field_container([
          udf('Billing Facility', subj, labelWidth:160, required: true, allowCreate:false, filter: "#{facility_filter}"),
          udf('Billing Facility Address', subj, labelWidth:160, anchor:'100%', height:40, required: true, validateAddress:true, react:{
            change:'form.setValuesAsync({id: value, udfs: {"Address":"Billing Facility Address"}})',
            only: 'Billing Facility'
          })
        ],
        react: {
          shown_when: "value == 'Facility'",
          only: 'Bill To'
        }
    )
    

    This example demonstrates how you can populate fields with values from another field. You can use the change listener to call either setValue or setValuesAsync (if you want to suspend listeners while the form is being populated).

    Filtering dropdowns in forms

    # In this example we only want to show tests that are already on the requisition, and are applicable to all specimen types or our specimen types
    udf('Tests', nil, value:tests, required:true, allowCreate:false,
        filter: "<-Requisition::\"Tests\" = #{req.id} AND (\"Specimen Types\" = #{specimen.id} OR \"Specimen Types\" = null)",
        react: {
          change: "
            this.setFilter(\'<-Requisition::\"Tests\" = #{req.id} AND (\"Specimen Type\" = \'+value+' OR \"Specimen Types\" = null)');
            this.setValue(#{tests_by_specimen.to_json}[value]);",
          only: 'Specimen Type'
        }),
    # Here we only want to see tests that are not archived and are orderable (i.e clients can order them)
    udf('Non-Orderable Tests', nil, value:non_orderable_tests, filter: 'terminated = false AND "Non-Orderable" = true', allowCreate:false),
    

    This example demonstrates how you can filter the values of dropdowns by a criteria or an expression. There are multiple ways to set filters.

    1. The simplest way to filter something is to set the filter property on a UDF, like so: filter:"terminated is false",.
    2. You can plug in your variables into the ruby template by following this example: filter:"Facility = #{facility ? facility.id : 0} and terminated is false"
    3. You can also pass in a filter expression like so: filter: "#{facility_filter}")
    4. Filter by state: filter: "#state = Active""

    UI class methods

    udf('Requesting Physician', subj, addCustomFields: physician_layout(subj, 2), labelWidth:160, required:true,
      filter:"Facility = #{facility ? facility.id : 0} and terminated is false",
      react: {
        shown_when: 'value',
        change: "this.setFilter('terminated is false and Facility='+(value || 0));",
        only:'Facility'
    }),
    

    udf

    Creates a UDF (user defined field).

    Parameter Description
    :name UDF name
    :subj Subject containing the UDF
    :options The options object
     field_row([
      udf('Decimal Places', subj),
      udf('Unit', subj, labelWidth:60)
    ]),
    

    field_row

    Creates a field row by taking an array of fields and laying them out in one row

    Parameter Description
    :items Array of items to place into a form row
    :options The options object
    field_container(fields, defaults: {anchor:'100%', labelWidth:160}, react:{
      init: 'this.setDisabled(!value)',
      only: 'Patient'
    })
    

    field_container

    Lays out passed in items in a field container. Useful if you want to apply the same styling to all items within a container

    Parameter Description
    :items Array of items to place into a form row
    :options The options object
    # Example fieldset
    field_set(title:'General Information', border:'1 0 0 0', defaults:{anchor:'100%'}, items:[])
    

    field_set

    Creates a ExtJs 4.2.2 fieldset with the given options

    Parameter Description
    :options The options object

    choice_by_query

    Creates a Choice type UDF but with the drop-down list filled by query

    Parameter Description
    :name The UDF name
    :subj Subject containing the UDF
    :query The query object that will produce a set of results to populate the picklist
    :options The options object to pass to the picklist

    custom_radio_group

    Creates a radio group from given options

    Parameter Description
    :args A configuration object, consisting of args[0] = name for the radio group and args[1] = the options object.

    The options object can contain an items property with each item having a name and checked properties.

    udfs_for_subject_type

    Returns a list of UDFs that exist for a given subject type in Limfinity

    Parameter Description
    :st The subject type
    :subj Subject containing the UDF
    :customizations Object containing any additional properties for the UDFs such as "readOnly", or "anchor
    subj = UI.add_subject('Analyte', params, {name: name})
    

    add_subject

    Creates a subject populated with the values from the params

    Parameter Description
    :st The subject type
    :params The params (usually from the custom form/view)
    :options The options object
    UI.save_subject(subj, params, name != subj.name ? {name: name} : {})
    

    save_subject

    Saves a subject populated with the values from the params. This method performs access controlled read and write operations, and writes to the audit trail.

    Parameter Description
    :subject The subject to save
    :params The params (usually from the custom form/view)
    :options The options object. If the options object contains "name" or "gen:name" properties, they will be used to create a new subject name
     opts = count ? {count: count} : {}
     ScriptRunner::UI::search_tab_link(subj_type_name, query, "style=\"color:white; text-decoration:none;\" onmouseover=\"this.style.color='black'\"  onmouseout=\"this.style.color='white'\"", tab_name, opts)
    

    Generates a link opening a search tab or showing '0' if nothing found

    Parameter Description
    :subject_type_name The subject type to search
    :query The query to run the search
    :tab_opts Object containing tab parameters
    :link_attrs Link attributes
    :tab_anem Name for the new tab
    #Example for Group Edit Component - display grid
    # Displays a grid with 4 rows, each containing an editable collection kit record
    params[:tool_message] = "Create up to 5 Collection Kits<br><br>"
    extend ScriptRunner::UI
    column_configs =  {
        'Quantity' => {minValue: 1}
      }
    
    params[:custom_fields] = encode_fields([
       group_editor('Add_Collection_Kits', [
         {0=>subj.get_value('Facility'), 3=>0},
         {0=>subj.get_value('Facility'), 3=>0},
         {0=>subj.get_value('Facility'), 3=>0},
         {0=>subj.get_value('Facility'), 3=>0}
         ], name: 'custom[data]', flex: 1)
    ])
    params[:custom_fields_place] = 'top'
    
    
    # script here to process the data from the Group Edit table
    # This script reads all the data out of each row and creates one collection kit per row
    # The editable fields are defined in the "Add Collection Kits" workflow tool
    extend ScriptRunner::UI
    names = []
    count = 0
    data = parse_group_edit_data(params['data'])
    data.each do |row|
      quantity  = row.fetch(row.keys.find{|p|p[:display_name] == 'Quantity'})
      specimen_type = row.fetch(row.keys.find{|p|p[:display_name] == 'Specimen Type'})
      facility = row.fetch(row.keys.find{|p|p[:display_name] == 'Facility'})
      components = row.fetch(row.keys.find{|p|p[:display_name] == 'Kit Components'})
    
      if quantity > 0
        for i in 1..quantity
            kit = create_subject('Collection Kit') do |kit|
            kit.set_value('Facility', facility)
            kit.set_value('Specimen Type', specimen_type)
            kit.set_value('Kit Components', components)
            kit.advance_workflow('Collection Kit', 'Requested')
            count += 1
          end
        end
     end
      end
    show_alert("Created #{count} Collection Kits") if count != 0
    

    group_editor

    Embeds an editable grid within a dialog

    Parameter Description
    :tool The instance of the subject group edit tool defined in the workflow builder
    :content An array containing the configuration for each row that will be displayed in the embedded grid.
    :options An array of options: payloads, column configs or anything else that needs to be passed ot the component

    select_template_field

    ?????????????

    Parameter Description
    :subject_type The name of the subject type
    :options An array of options

    select_printer_field

    ?????????????

    Parameter Description
    :options An array of options

    Sending Emails

    # In this example, an array of recipients is first create,d and then an email is setn to the recipients using an email template by the name of "Example Template", regarding the opened subject
    # Create an array of recipients
    recipients = []
    
    # Add all members of the "User Group 1" group to the recipients array
    recipients << find_user_group('User Group 1)
    # Add all members of the "User Group 2" group to the recipients array
    recipients << find_user_group('User Group 2)
    
    # Send an email using the email template "Example Template" regarding the current subject
    send_email( recipients , find_email_template('Example Template'), subj)
    

    Limfinity supports the automatic sending of emails through scripts, if the installation is set up with proper emailing credentials. The send_email() method is used to send emails to users with registered email addresses to their user accounts.

    In this example, an array of recipients is first created. Recipients can be specific users, or entire user groups. User groups are added to the recipients array in this case. After the recipients have been assigned, the send_email() method is called. The method takes the first parameter of the recipients, the second of the defined email template, and the last parameter of the opened subject. *Note that an email template is always required to send an email. Email templates must be created in the system in order to successfully send an email.

    Sending an email with a file attachment

    # recipient email address
    email_addr = 'test@brooks.com'
    
    # This is the email template in the system
    template = "Email Test"
    
    # This is the 'File' UDF set in the 'Script Parameter'
    if params['ATTACHED FILE'].present?
        file = params['ATTACHED FILE']
        subj.set_value('ATTACHED FILE', file)
    end
    
    # the attached file
    rfile = subj.get_value('ATTACHED FILE')
    
    send_email(email_addr, template, subj) do |e|
        e.add_attachment(rfile, rfile.to_s, rfile.to_json['mime_type'])
    end
    
    show_message('Email sent')
    

    Files can be attached to the email using ‘File’ UDF. When creating the email workflow tool, the field ‘Script Parameter’, which is the ‘File’ UDF, needs to be selected. The After Script will contain the reference of the script parameters.

    Errors

    The Lifinity API uses the following error codes:

    Error Code Meaning
    400 Bad Request -- The request is incorrect.

    API

    List of Objects Supported by Limfinity API

    AuditRec

    A record of any change within the system.

    Parameter Description
    :id Unique ID of an audit record.
    :obj_name Name of the changed object.
    :user The name of the user that made the change.
    :obj_type The type of the object changed.
    :created_at The date the audit record was created.
    :message The action performed that created the audit.
    :comments Any user-generated comment added when the audited action was performed.

    Auth_token

    An authorization token used in place of a user’s password for API calls. Using the auth_token will omit the “API Session Created” and “API Session Removed” entries in the audit log.

    Users

    Uniquely identifies a user in the system:

    Parameter Description
    :id Unique ID of a user.
    :username User’s Login name.
    :fullname User’s full name.
    :email User’s email.
    :created_at Date when the user was created in the system.
    :roles Roles assigned to the user.
    :disabled Defines whether the user is currently disabled.
    :locked = Defines whether the user is currently locked.
    :active Defines whether the user is currently active.
    :groups List of User Groups this user belongs to.

    Group

    Uniquely identifies a user group in the system:

    Parameter Description
    :id Unique ID of a user group.
    :name User group’s name.
    :description Description of the group.
    :created_at Date when the group was created in the system.
    :created_by User name who created this group.
    :updated_at Date when the group was last updated.
    :users-count Number of users in the group.
    :baseline Placeholder text.

    Role

    A role that defines the access permissions in the system:

    Parameter Description
    :id Unique ID of a role.
    :name Role’s name.
    :rights A list of rights assigned to the role.
    :baseline Placeholder text.
    :created_at Date when the role was created in the system.
    :system_role Defines whether the role is internal (built-into the software) or user-defined.

    UserField

    A user-defined field in the system:

    Parameter Description
    :id Unique ID of a user-defined field.
    :name Internal name of the user-defined field.
    :display_name Display (human readable) name of user-defined field.
    :type User-defined field type (“Date”, “Text Field”, “Text Area”, “Checkbox”, etc.) :searchable = Defines whether the user-defined field is searchable.
    :values User-defined field values.
    :created_at Date when the user-defined field was created in the system.
    :updated_at Date when the user-defined field was last updated.
    :created_by User name who created this user-defined field.
    :used_by Which objects use the user-defined field.
    :permission Permissions applicable to the user calling a method which returns this object.

    SubjectType

    A user-defined subject type in the system:

    Parameter Description
    :id Unique ID of a subject type.
    :name Internal name of the subject type.
    :descr Description of the subject type.
    :color Color of the icon representing the subject type.
    :searchable_quick Defines whether the subject type may be found in a quick search. :searchable_advanced = Defines whether the subject type may be found in an advanced search. :searchable_batch = Defines whether the subject type may be found in a batch search.
    :fields List of user-defined properties.
    :searchable The subject type is searchable within the system.
    :syslock Indicates if the object is “locked” in the configuration, and can’t be changed regardless of the site. :baseline = Indicates if the object is part of the baseline configuration.
    :created_at Date when the subject type was created in the system.
    :updated_at Date when the subject type was last updated.
    :created_by User name who created this subject type.
    :enabled Enabled or disabled flag for this subject type.
    :permission The permissions available to this subject type.
    :configuration The subject type is part of the system configuration.
    :fields_count Number of user-defined fields in this Subject Type.

    SubjectTypeGroup

    A user-defined group of subject types in the system:

    Parameter Description
    :id Unique ID of a subject type group.
    :subject_types The subject types associated with this group.
    created_at Date when the subject type group was created.
    baseline Indicates if the object is part of the baseline configuration.
    updated_at Date when the subject type group was last updated.
    created_by: User name who created this subject type group.

    Subject

    Any user object in the system. Subjects are instances of a particular Subject Type:

    Parameter Description
    :id Unique ID of a subject.
    :name Subject name.
    :barcode_tag The unique barcode number assigned to the subject. :rid_tag = The unique RFID number assigned to the subject. :subject_type = Subject type name (Example: Bacteria or Sample).
    :created_at Date when the subject was created in the system.
    :updated_at Date when the subject was last updated.
    :terminated Flag if subject is terminated and no longer part of process/workflow. :user = Username of a subject owner.
    :permission The permissions available to this subject.
    :flow_states Workflow states which the object has been in.
    :created_by The user that created the subject.
    :updated_by The user that last updated the subject.
    :udfs The number and names of all user-defined fields associated with this subject.

    List of API Functions

    Returned Objects

    LIMFINITY objects returned by API function.

    Required Parameters

    Necessary parameter or parameters for the method to run correctly. Without the required parameters an error message from the server should be expected. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.

    Optional Query parameters

    Optional parameters to control the results. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.

    Optional Control parameters

    Optional parameters to control the number and order of records in the output, and to implement paging of the results. These will be written in the format required for the script along with placeholder text within the ‘ ’ marks.

    audit

    #Example #1 - This API will print the total number of Audit Records and list all related information.
    #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :date_flag=>'all/today/yesterday/week/month': Allows user to search for a specific date #, :date_range=>'date from,date to': Allows user to search a specific date range
    #, :subj_ids=>'value,value': comma-separated Subject IDs to get audit records
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'text': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'audit'#Copy and paste optional query and/or control parameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "AuditRecs"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s)
          end
        end
      end
    end
    

    Retrieves a list of audit records of every change made within the system.

    Property Parameter Description
    Returned Objects: AuditRecs
    Required Parameters: None
    Optional Query Parameters :date_flag=>’all/today/yesterday/week/month’ Displays audit records made today, yesterday, this week, or this month.
    :date_range=>’date_from,date_to’ Displays audit records made within a specific date range(format: mm/dd/yyyy).
    :subj_ids=>’value,value’ Displays audits records of a specific range of subjects.
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of items to retrieve.
    :sort=>'text' Sort the displayed results by a specific field such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    users

    #Example #2 - This API will print the total number of Users and list all related information.
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'users'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "Users"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s)
          end
        end
      end
    end
    

    Retrieves a list of users within the system.

    Property Description
    Returned Objects Users
    Required Parameters None
    Optional Query Parameters None
    Optional Control Parameters None

    users_groups

    #Example #3 - This API will print the total number of User Groups and list all related information.
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'user_groups'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "Groups"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s)
          end
        end
      end
    end
    

    Retrieves a list of user groups within the system.

    Property Description
    Returned Objects Groups
    Required Parameters None
    Optional Query Parameters None
    Optional Control Parameters None

    roles

    #Example #4 - This API will print the total number of Roles and list all related information.
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'roles'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "Roles"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s) end
        end
      end
    end
    

    Retrieves a list of roles within the system.

    Property Description
    Returned Objects Roles
    Required Parameters None
    Optional Query Parameters None
    Optional Control Parameters None

    userfields

    #Example #5 - This API will print the total number of User Fields and list all related information. #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :query=>'text': optional search string to filter the results.
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'value': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'userfields'#Copy and paste optional query and/or co ntrol parameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "UserFields"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s) end
        end
      end
    end
    

    Retrieves a list of user-defined fields within the system.

    Property Parameter Description
    Returned Objects UserFields
    Required Parameters None
    Optional Query Parameters :query=>’text’ Displays a list of user-defined fields containing a specific text string.
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of results to retrieve.
    :sort=>'text' Sort the displayed results by a specific field such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    subject_types

    #Example #6 - This API will print the total number of Subject Types and any relevant information
    #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :query=>'text': optional search string to filter the results.
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'value': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'subject_types'#Copy and paste optional query and/or control parameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "SubjectTypes"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s) end
        end
      end
    end
    #puts data
    

    Retrieves a list of subject types within the system.

    Property Parameter Description
    Returned Objects SubjectTypes
    Required Parameters None
    Optional Query Parameters :query=>’text’ Displays a list of subject types containing a specific text string.
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of results to retrieve.
    :sort=>'text' Sort the displayed results by a specific field such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    subject_groups

    #Example #7 - This API will print the total number of Subject Type Groups and any relevant informatio n
    #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :query=>'text': optional search string to filter the results.
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'value': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'subject_groups'#Copy and paste optional query and/o r control parameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "SubjectTypeGroups"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s) end
        end
      end
    end
    #puts data
    

    Retrieves a list of subject type groups within the system.

    Property Parameter Description
    Returned Objects SubjectTypes
    Required Parameters None
    Optional Query Parameters :query=>’text’ Displays a list of subject type groups containing a specific text string.
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of results to retrieve.
    :sort=>'text' Sort the displayed results by a specific field such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    subjects

    #Example #8 - This API will print the total number of Subjects and any relevant information
    #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :subject_ids=>'value': limit subjects to a list of IDs
    #, :subject_names=>'text': limit subjects to a list of names
    #, :user_fields=>'text': comma-delimited list of User Defined fields to retrieve for subjects #, :query=>'text': optional search string to filter the results.
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'value': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'subjects', :subject_type=>'Patient'#Copy and paste optional query and/or control parameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    puts data
    data.each do |key,value|
      if key == "Subjects"
        value.each do |types|
          puts "--------------" types.each do |k,v|
            puts (k.to_s + ": " + v.to_s)
          end
        end
      end
    end
    #puts data
    

    Retrieves a list of subjects within the system.

    Property Parameter Description
    Returned Objects Subjects
    Required Parameters :subject_type=>’value/text’ Limits the search to all subjects of a specific type(can use subject type name or specific ID).
    Optional Query Parameters :subject_ids=>’value,value’ Limits subjects to a list of item specific IDs.
    :subject_names=>’text,text’ Limits subjects to a list of item specific names.
    :query=>’text’ Displays a list of subjects containing a specific text string.
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of results to retrieve.
    :sort=>'text' Sort the displayed results by a specific field such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    delete_subject

    #Example #9 - This API will delete a Subject as specified by ID or a combination of subject_type/subj ect_name
    #add any of the Optional query parameters by copy and pasting <, :function=>'value'> after <:method=> ''>
    #, :subject_type=>'value': subject type ID
    #, :subject_name=>'text': subject name
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url  = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks
    req  = Net::HTTP::Post::Multipart.new url.path,
                                          :username=>'admin', :password=>'admin', :method=>'delete_subject', :id=>'13'#replace <:id=>'value '> with <:subject_type=>'value', :subject_name=>'text'> for optional query parameters
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    puts "-------------------"
    puts data.to_json
    puts "-------------------"
    

    Deletes a subject as specified by ID.

    Property Parameter Description
    Returned Objects None
    Required Parameters :id=>’value’ The specific ID of the subject to be deleted, OR
    :subject_type=>’value/text’ Limits the search to all subjects of a specific type(can use subject type name or specific ID).
    :subject_name=>’text’ Limits the search to all subjects matching the specified name
    Optional Query Parameters None
    Optional Control Parameters None

    gen_token

    #Example #10 - This API will generate and print an "auth_token" to be used instead of a user's pass word. Using the auth_token will omit the API Session Created
    # and API Session Removed  entries in the audit log
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks = Net::HTTP::Post::Multipart.new url.path,
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'gen_token'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    str = res.body
    puts str #Output the generated authentication token
    

    Creates an “auth_token” to be used instead of a user’s password. Using the auth_token will omit the “API Session Created” and “API Session Removed” entries in the audit log.

    Property Description
    Returned Objects Auth_token
    Required Parameters None
    Optional Query Parameters None
    Optional Control Parameters None

    subject_details

    #Example #11 - This API will Print all details of a Subject as specified by ID, Barcode, and RFID
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks 8.
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'subject_details', :subject_id=>'9',
                                         :barcode_tag=>'L04000009', :rfid_tag=>'355AB1CBC000004000000009'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    
    data.each do |key,value|
      puts (key.to_s + ": " + value.to_s)
    end
    

    Deletes a subject as specified by ID.

    Property Parameter Description
    Returned Objects A list of values corresponding to a specific subject
    Required Parameters :id=>’value’ The specific ID of the subject to be displayed.
    :barcode_tag=>’value’ The specific barcode tag of the subject to be displayed.
    :rfid_tag =>value The specific RFID tag of the subject to be displayed.
    Optional Query Parameters None
    Optional Control Parameters None

    run_script

    #Example 12 - This API will execute a run_script / helper script by specifying the name of the script in the system and the data which should be passted to it.
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://demo.limfinity.com/api') 8.
        req = Net::HTTP::Post::Multipart.new url.path, :username=> "admin",
                                             :password=> "admin",
                                             :name=> "demo_helper_script",
                                             :data=> { "Name": "Sample 1", "BARCODE": "123456", "Specimen Name": "Specimen 1", "Created": "10/28/2014", "Created By": "User 1", "Current Amount": 10.2 }
    
    res = Net::HTTP.star(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    puts data.to_json
    

    Allows the running of a helper script by name and the passing of arbitrary JSON-formatted parameters to that script.

    Property Parameter Description
    Returned Objects Helper script-returned serialized JSON
    Optional Query Parameters None
    Optional Control Parameters None
    Required Parameters :name=>’helper_script_name’ The name of the helper script to be run.
    :data=>’’ Arbitrary data to be passed to the script represented as a JSON object(s) of a string wit JSON-encoded object(s). This data will be accessible in the script as data.

    The script will also have access to all HTTP request parameters specified in the request using params[:parameter_name] syntax

    This function differs from all other API functions by how it should be called. Instead of passing run_script as a value for the “method” parameter, is requires a special URL in the following form: http://{LIMS_ADDR}:{LIMS_PORT}/api/run_script

    Example

    search_subjects

    #Example #13 - This API will search for a Subject by variables such as Subject Type, Search Mode, Use r Fields, and texts strings.
    #add any of the optional control parameters by copy and pasting <, :function=>'value'> after <:method =>''>:
    #, :start=>'value': specifies what record to start listing from
    #, :limit=>'value': limit number of records to retrieve
    #, :sort=>'value': sort the records by a specific value
    #, :dir=>'ASC/DESC': sort the records in ascending or descending order
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks)
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin',
                                         :method=>'search_subjects', :subject_type=>'Client', :search_mode=>'REGULAR',
                                         :user_fields=>'Address, Phone Number',
                                         :fields=>'Subject Name', :conditions=>'contains', :values=>'brooks'#Copy and paste optional control par ameters here
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    data.each do |key,value|
      if key == "Subjects"
        value[0].each do
          puts (k.to_s|k,v| +":"+v.to_s)
        end
      end
    end
    

    Retrieves a subject or list of specified subjects.

    Property Parameter Description
    Returned Objects Subjects
    Required Parameters :search_mode=>’REGULAR/DEEP’ Specifies the type of search to be performed.
    :subject_type=>’value/text’ Limits the search to all subjects of a specific type(can use subject type name or specific ID, Example: ‘Client’).
    :user_fields=>’text,text’ Comma delimited list of User-defined fields to retrieve for the searched subject(s)(Example: ‘Address, Phone Number’).
    :fields=>’text’ fields to search within the subject(Example: ‘Subject Name’)
    :conditions=>’text’ The conditions that will be applied to the search subject. :values=>’value/text’ = Specific strings within the subject to be searched for.
    Optional Query Parameters None
    Optional Control Parameters :start=>’value’ The item specific ID to start the list with.
    :limit=>'value' The total number of results to retrieve.
    :sort=>'text' Sort the displayed results by a specific identifier such as subject_type, subject_name, etc.
    :dir=>'ASC/DESC' Sort the displayed results in ascending or descending order.

    import_subjects via CSV

    #Example #14 - This API will import Subjects based on a CSV filerequire 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks) 8.
    
    File.open("./clients.csv") do |the_csv|
    
      req = Net::HTTP::Post::Multipart.new url.path,
                                           :file=> UploadIO.new(the_csv, "text", "clients.csv"), :username=>'admin', :password=>'admin',
                                           :method=>'import_subjects', :subject_type=>'Client'
    
      res = Net::HTTP.start(url.host, url.port) do |http|
        http.request(req)
      end
    
      data = JSON.load(res.body)
      puts "Total Success" if data['success']
      puts data['message'] #success or error message will be printed here
    end
    
    

    Imports a subject or subjects along with specified fields from a CSV file.

    Property Parameter Description
    Returned Objects Subjects
    Required Parameters :file=>’.CSV file’ File to import(Must be CSV format).
    :subject_type=>’value/text” The specific type of the subject or subjects to be imported.
    Optional Query Parameters None
    Optional Control Parameters None

    import_subjects via JSON

    Imports a subject or subjects along with specified fields specified by subjects in JSON format

    Property Parameter Description
    Returned Objects None
    Required Parameters :json=>’’ String of LIMFINITY subjects in JSON format.
    :subject_type=>’value/text” The specific type of the subject or subjects to be imported.
    Optional Query Parameters None
    Optional Control Parameters None

    upload_file_udf

    #Example #15 - This API will upload a file to a Subject as specified by ID
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://your-limfinity-url/api')#Copy and paste actual URL within the '' marks)
    
    fname = 'C:\Users\Louis\Desktop\New Limfinity API Guide Examples\clients.csv'
    
    File.open("#{fname}") do |f|
    
      req = Net::HTTP::Post::Multipart.new url.path,
                                           :username=>'admin', :password=>'admin', :method=>'upload_file_udf',
                                           :file=> UploadIO.new(f, "text", fname), :id=>'2', :udf_name=>'File'
    
      res = Net::HTTP.start(url.host, url.port) do |http|
        http.request(req)
      end
    
      str = res.body
      puts str
    end
    

    Uploads a file containing user-defined fields to the system.

    Property Parameter Description
    Returned Objects None
    Required Parameters :udf_name=>’ text’ Name of the file to be uploaded.
    :file=>’text’ The content of the file to be uploaded.
    Optional Query Parameters None
    Optional Control Parameters None

    get_pedigree_data

    #Example #16 - This API will print the pedigree data of a Subject as specifed by ID
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://demo.limfinity.com/api')#Copy and paste actual URL within the '' marks)
    
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :password=>'admin', :method=>'get_pedigree_data',
                                         :subject_type=>'Patient', :subject_id=>'12345'
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    
    data.each_pair do |key, value|
      if key.is_a?(Numeric) #has assigned patient
        patient = value[:Individual]
        father = value[:Father]
        if father
          father_id = father.is_a?(Subject) ? father.id : father
          father_data = data[father_id]
          puts father_data #output father data
        end
        mother = value[:Mother]
        if mother
          mother_id = mother.is_a?(Subject) ? mother.id : mother
          mother_data = data[mother_id]
          puts mother_data #output mother data
        end
      else #No assigned patient
        puts "No assigned patient"
      end
    end
    

    Retrieves the pedigree data of one family within the system.

    Property Parameter Description
    Returned Objects Key/value pair pf pedigree node subject and its information.
    Required Parameters :family_subject=>’value/text’ Family subject type(can use subject type name or specific ID).
    :pedigree_prop=>’text’ Pedigree type user-defined field or its name(not required if there is only one user-defined field for this type
    Optional Query Parameters None
    Optional Control Parameters None

    Returned Hash Values

    he key is an individual ID of a pedigree node. The key is the numeric subject ID for the pedigree nodes with the assigned subject, or a string otherwise. The value is a hash with the following content(each pair is optional).

    Property Description
    :Individual Assigned subject.
    :Mother Subject if the mother node has an assigned subject; String ID otherwise.
    :Father Subject if the father node has an assigned subject; String ID otherwise.
    :Gender ‘Male’ or ‘Female’.
    :Sampled, :MZTwin, :DZTwin, :Proband, :Deceased, :Consultand, :Carrier, :Affected Same as in the standard PED format.
    :terminated_pregnancy “true” if the pregnancy was terminated.
    :adopted_in “true” if the individual was adopted in
    :adopted_out “true” if the individual was adopted out.

    Using auth Token

    #Example #17 - The purpose of this API is to test if an auth token generated by "Example 10 Gen Token.rb" works as intended if used instead of a password.
    require 'rubygems'
    require 'json'
    require 'net/http'
    require 'net/http/post/multipart'
    
    url = URI.parse('http://demo.limfinity.com/api')#Copy and paste actual URL within the '' marks
    
    req = Net::HTTP::Post::Multipart.new url.path,
                                         :username=>'admin', :auth_token=>'9bdc7e45-e541-4867-9077-6ff181876118', :method=>'users'#copy and paste generated auth token in <:auth_token=>''>
    
    res = Net::HTTP.start(url.host, url.port) do |http|
      http.request(req)
    end
    
    data = JSON.load(res.body)
    total = data['Total']
    puts total
    puts data
    data.each do |key,value|
      if key == "Users"
        value.each do |types|
          puts "--------------"
          types.each do |k,v|
            puts (k.to_s + ": " + v.to_s)
          end
        end
      end
    end
    

    This example is not linked to a corresponding method. The purpose of this example is to demonstrate how to use an auth token returned by “Example 10 Gen Token.rb”.

    suffix = subj.get_value('Program Identifier')
    url= 'https://clinicaltrialsapi.cancer.*9'
    

    Calling External APIs with Limfinity

    User can use call_external_service in After Script with optional :get, :post(default), and :put to specify the HTTP methods

    Guides

    Modelling your data with Limfinity

    This guide walks you through the process of replicating your data model with Limfinity. In this guide you'll learn how to:

    In the sections below, we'll create a "Patient" subject that will be linked to a "Sample.

    Step 1: Create a new Subject Type

    A Subject Type defines the type of data you can store. Think of it as a form, or a table.

    Each subject type is annotated with user-defined fields (UDFs) that capture the metadata for that object. Each instance of a subject type is called a subject.

    1. Log in and click on Settings and Preferences
    2. Click on Subject Types
    3. Click the plus button to create a new Subject Type New Subject Type New Subject Type
    4. Name your Subject Type "Patient" and specify the Plural Name - Patients Plural Name
    5. Click OK to save

    Step 2: Adding User-Defined-Fields to your Subject Type

    Now we have a new "Patient" subject type, but it has no fields. Let's add a couple:

    1. Click on the "Patient" subject type
    2. Click on the Add User Defined Field button and choose Date as the field type
    3. Enter "DOB" for the User Field Name and check Advanced Search New UDF
    4. Let's add a couple other fields: Phone Number (Text Field), Consent Signed (Checkbox), Gender (Choice - Male, Female, Both), Comments (Text Area)
    5. Click OK to Save

    Let's also create another subject type and name it "Sample" with the field Amount (Numeric). What we want to do now is to link the sample to the patient it has been collected from.

    1. Open the "Sample" subject type
    2. Click on Add User Defined Field button and choose Limfinity -> Subject as the field type
    3. Enter "Patient" as the User Field Name and select Patient as the `Subject Type New UDF
    4. Click OK to Save

    Step 3: Creating a subject

    Our 'Patient' subject type has fields defined, but we do not yet have any actual patients.

    Let's make a patient:

    1. Click on Explorer
    2. Click on Patients
    3. Click the plus button to add a new subject
    4. Enter values for DOB, Gender, Consent Signed, Phone number, Comments and click OK to save the new subject New UDF

    Configuring the subject type grid

    Our newly added fields are not yet showing up on patient result grids. Let's configure the grid and add our new fields:

    1. Click on Settings and Preferences
    2. Click on Subject Types
    3. Select Patient and click View Options
    4. Add fields DOB, Gender, Phone Number, Consent Signed and Comments
    5. Remove the UID field
    6. Move the fields DOB, Gender, Phone Number and Consent Singed to the top and click OK New UDF

    Creating workflows

    This guide walks you through the process of creating a workflow. In this guide you will learn how to:

    In the sections below, we'll create an "Issue" workflow. Let's start by creating an "Issue" subject type with fields:

    1. Description (Text Area)
    2. Status (Choice)
    3. Assignee (User)
    4. Resolved Date (Date)

    Step 1: Create a new Workflow

    Each workflow can only be attached to one single subject type, but subject types can belong to multiple workflows. A workflow describes how subjects go through processes and what actions are available for each state

    1. Click on Settings and Preferences
    2. Click on the plus button and select the desired subject type ("Issue)
    3. Enter a name for the workflow. The convention is to name it the same as the subject type, so let's put in "Issue" as the worklfow name
    4. Click on the workflow to open it in the workflow editor window New UDF

    Step 2: Add states

    We have a brand new "Issue" workflow, but it has no states. Each record in the workflow will go through a sequence of states that model the workflow. For our "Issue" workflow, we know that it can either be "Open" or "Resolved". 1. Click on the plus button to add a new state New UDF 2. Let's call the new state "Open". This new state will appear on the canvas. By default, this state will be the entry state for all new subjects in the "Issue" workflow, but you can always change the first state by specifying a new "Entry State" in workflow editor 3. Create another state called "Resolved" New UDF

    Step 3: Adding a workflow transition

    Now that we have both "Open" and "Resolved" states, let's link it together. To do this, you will need to create a tool (it can be any type of tool) 1. Click on the plus button in the Tools tab 2. Give your tool a name, and a title. Name is the internal identifier, while Title is the user-facing value 3. Specify the Input Subject Type = Issue 4. Specify the Workflow Transition = Resolved 5. Drag the tool into the "Open" state New UDF 5. You should now see an arrow stretch the "Open" state to the "Resolved" state New UDF

    Let's add another tool to create a new Issue:

    1. Create a Create New Subject tool and name it "New Issue"
    2. Fill out the Name, Title, Output Subject Type, and Workflow
    3. Click OK to create a new Issue record

    Step 4: Adding tool groups

    Starting with Limfinity 7.1 you can now reuse individual tools or multiple tools in many workflows by placing them into tool groups. Tool groups can be used in many places such as Quick Links (buttons that appear in the left nav bar) or workflows.

    To create a toolgroup:

    1. Click on the plus button in the Tool Groups tab
    2. Fill out the Name = Issues and the Title = Issues fields New UDF
    3. You can specify whether to display the tool group as a quick link, or as a set of buttons on the workflow state. Let's place this toolgroup in the Quick Links bar.
    4. Add the "Resolve" and the "New Issue" tools to this tool group
    5. Refresh to see a folder with the workflow tools

    Step 5: Taking a subject record through a workflow

    Let's take an Issue from being open to resolution:

    1. Click on Explorer. and select Issues
    2. Click New Issue
    3. A "New Issue" dialog will open
    4. Fill out the data to create a new Issue
    5. Upon saving, the page for the new record will open and you should see a "Resolve" button on the right of the page