IRB Exchange

Show / Hide Table of Contents

Reportable New Information

Reportable New Information filed on the participating site side may need to be uploaded to the IRB Exchange if the related submission is an external study downloaded from the IRB Exchange and either IRB staff decisions and/or institution policy dictate the reportable new information be reviewed by the sIRB.

What's Involved

  1. Adding a method to create JSON representing a reportable new information submission.
  2. Adding two attributes to the Reportable New Information CDT to store reported by string and last action response ID.
  3. Adding a method to create reportable new information submission on sIRB side.
  4. Adding a method to parse JSON representing a reportable new information submission and set the data on the submission.
  5. Modifying the Submit Action Response activity to call a method to upload an action response to the IRB Exchange.
  6. Adding a Submit Action Response (Admin) activity that can be called by script on the sIRB side to record submitted action responses from the participating site side.
  7. Adding a method to parse JSON representing an action response and record that activity on the reportable new information submission on the sIRB side.
  8. Modifying the Pre-Submission -> Pending sIRB Review state transition to upload the reportable new information submission to the IRB Exchange.

Create Reportable New Information JSON

_IRBSubmission.toRniJson Method Example

/** Converts the relevant data for an RNI into JSON for upload to the IRB Exchange.
 *
 * @param activity (_IRBSubmission_SubmitActionResponse) Submit Action Response activity supplying action response when this is triggered by that
 * @param mss (_IRBSubmission) The study the RNI is related to
 *
 * @returns {{JSON}}
 */
function toRniJson(activity, mss) {
    var jsonObj = {};

    // Set scalar data
    jsonObj.poRef =                         this + "";
    jsonObj.studyPoRef =                    mss + "";
    jsonObj.name =                          this.getQualifiedAttribute("name");
    jsonObj.dateOfAwareness =               this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.dateOfAwareness");
    jsonObj.description =                   this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.descriptionOfProblem");
    jsonObj.isIncreasedRiskOrSafetyIssue =  this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.isIncreasedRisk");
    jsonObj.requiresProtocolRevision =      this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.requiresProtocolRevision");
    jsonObj.requiresConsentFormRevision =   this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.consentRequiresRevision");
    jsonObj.principalInvestigator =         mss.getQualifiedAttribute("customAttributes.leadInvestigator.customAttributes.studyTeamMember").fullName();
    jsonObj.sitePrincipalInvestigator =     mss.getQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember").fullName();
    jsonObj.reportedBy =                    this.getQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember").fullName();
    if(activity != null) {
        jsonObj.actionResponseNotes =       activity.getQualifiedAttribute("notesAsStr");
    }

    // Selection sets
    jsonObj.categories =                    getSelectionSetIds(this, "customAttributes.reportableNewInformation.customAttributes.category", "ID");

    // Document sets
    jsonObj.supportingDocuments =           getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.supportingDocuments"));
    if(activity != null && activity.getType() == "_IRBSubmission_SubmitActionResponse") {
        jsonObj.actionResponseDocuments =   getDocSetPoRefs(activity.getQualifiedAttribute("documents"));
    }

    return JSON.stringify(jsonObj, null, null);
}

Technical note about this method example:

  • For convenience, we included any action response along with the reportable new information submission data.

Add Attributes

Add a string attribute to the Reportable New Information CDT called Reported by as String. This will store a string concatenation of the first and last name of the person who reported the new information on the participating site side for display on the sIRB side.

Add another string attribute to the Reportable New Information CDT called Last Action Response Id that will store the unique ID of the last action response downloaded from the IRB Exchange.

Create Reportable New Information Submission

_IRBSubmission.createExternalRniFromExchange Method Example

/** Creates an external RNI from the IRB Exchange.
 @param rniJson (JSON) The RNI's data
 @param exchangeClient (IrbExchange) Entity with methods to run on the IRB Exchange
 @return returnObj (JSON) - The new external RNI and the related study
 **/
function createExternalRniFromExchange(rniJson, exchangeClient) {
    var sch = ShadowSCH.getRealOrShadowSCH();
    var currentUser = Person.getCurrentUser();

    // Create the external RNI
    var submissionType = getResultSet("_SubmissionType").query("ID = 'RNI'").elements.item(1);

    // Create the external RNI and fill in some basic info
    var newExternalRni = _IRBSubmission.createEntity();
    newExternalRni.setQualifiedAttribute("dateCreated", new Date());
    newExternalRni.setQualifiedAttribute("dateModified", new Date());
    newExternalRni.setQualifiedAttribute("customAttributes.canDownloadExchangeUpdates", true);
    newExternalRni.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.isSIRBExternal", false);
    newExternalRni.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.createdByPSite", true);
    newExternalRni.setQualifiedAttribute("customAttributes.submissionType", submissionType);
    newExternalRni.setID();
    newExternalRni.setQualifiedAttribute("resourceContainer", ResourceContainer.createEntity());
    var irbSettings = _IRBSettings.getIRBSettings();
    newExternalRni.setQualifiedAttribute("customAttributes.irbSettings", irbSettings);
    newExternalRni.setQualifiedAttribute("status", GetElements("ProjectStatusForProjectTypeAndID", "ID", "Pre-Review", "projectType", "_IRBSubmission").item(1));
    newExternalRni.setQualifiedAttribute("createdBy", currentUser);
    newExternalRni.setQualifiedAttribute("currentSmartFormStartingStep", newExternalRni.getStartingWizardPageForRni());
    newExternalRni.setQualifiedAttribute("customAttributes.dateEnteredIRB", new Date());

    // Lookup study referenced by RNI related studies and relate it
    var study = wom.getEntityFromString(rniJson.studyPoRef);
    var sites = study.getQualifiedAttribute("customAttributes.mSSPSites");
    if(sites == null) {
        throw new Error("No sites for study with ID " + study.ID);
    }
    var matchingOrg = IrbExchangeReference.GetPoRef(rniJson.owner.exchangeRef, null, exchangeClient.GetEndpoint() + "");
    var matchingSite = sites.query("customAttributes.mSSPSiteInstitutionalProfile.customAttributes.institution = " + matchingOrg).elements();
    if(matchingSite.count() != 1) {
        throw new Error("Unexpected number of matching sites for study with ID " + study.ID);
    }
    var site = matchingSite.item(1);
    newExternalRni.setQualifiedAttribute("parentProject", site);
    newExternalRni.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.reportingSite", site);
    newExternalRni.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.relatedStudies", study, "add");
    newExternalRni.setQualifiedAttribute("company", site.getQualifiedAttribute("customAttributes.mSSPSiteInstitutionalProfile.customAttributes.institution"));
    newExternalRni.setQualifiedAttribute("resourceContainer.parent", site.resourceContainer);
    newExternalRni.setQualifiedAttribute("customAttributes.IRB", site.getQualifiedAttribute("customAttributes.IRB"));

    // Create the workspace
    newExternalRni.createWorkspace(Container.getElements("Container").item(1), newExternalRni.setWorkspaceTemplate());

    // Set the workspace template since a bug somewhere prevents createWorkspace from setting the correct template
    var theTemplate = newExternalRni.setWorkspaceTemplate();

    // Fill in rest of SmartForm data
    var documentsToDownload = newExternalRni.setFromRniJson(rniJson, study, exchangeClient, null);

    // Add a reference to the external RNI to the Exchange
    IrbExchangeReference.LinkExchangeIdToPoRef(rniJson.exchangeRef, newExternalRni + "", exchangeClient + "", exchangeClient.GetEndpoint() + "", true, false, false, false);

    // Set the submitter as the Primary contact and Investigator
    newExternalRni.setQualifiedAttribute("customAttributes.primaryContact.customAttributes.studyTeamMember", currentUser);
    newExternalRni.setQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember", currentUser);

    // Set parentStudy to point to itself as that's required for the security model
    newExternalRni.setQualifiedAttribute("customAttributes.parentStudy", newExternalRni);

    // Log creation in the history
    var rniOpenActivity = ActivityType.getActivityType("_IRBSubmission_ReportableInformationOpened", "_IRBSubmission");
    var openActivity = newExternalRni.logActivity(sch, rniOpenActivity, currentUser);
    openActivity.majorVersion = 0;
    openActivity.minorVersion = 1;

    // Check for current integration settings and trigger state changed event if integrated
    newExternalRni.triggerStateChangedEvent();

    // Standard hook to allow customers to add additional processing to workflow events.
    if (CustomUtils.hasTypeMethodNamed("onIRBSubmissionStateTransition")) {
        CustomUtils.onIRBSubmissionStateTransition(sch, newExternalRni, openActivity, currentUser);
    }

    newExternalRni.updateContacts("IRBC");

    var sessionContext = wom.getSessionContext();
    sessionContext.putContextObject(newExternalRni.ID + "-LastExchangeUpdate", new Date(), true);

    var returnObj = {};
    returnObj.study = study + "";
    returnObj.rni = newExternalRni + "";
    returnObj.documentsToDownloadArray = JSON.stringify(documentsToDownload, null, null);
    return returnObj;
}

Technical notes about this method example:

  • Attribute customAttributes.reportableNewInformation.customAttributes.isSIRBExternal is set to false. This is a flag that tracks whether the sIRB of the related submission is external to the local institution.
  • Attribute customAttributes.reportableNewInformation.customAttributes.createdByPSite is set to true. This is a flag that tracks whether the reportable new information was originally created on the participating site side.
  • The site that reported the new information is set as the reporting site.
  • The method _IRBSubmission.setFromRniJson is called to parse the JSON into the reportable new information submission's data.

Parse Reportable New Information JSON

_IRBSubmission.setFromRniJson Method Example

/** Takes JSON from the IRB Exchange for an RNI and sets the data onto the appropriate external RNI.
 *
 * @param rniJson (JSON) JSON of the RNI containing its data
 * @param study (_IRBSubmission) The related study
 * @param exchangeClient (IrbExchange) Handle to the etype to run operations on against the Exchange
 * @param activity (Activity) The activity being executed as part of the update from Exchange
 *
 * @returns {JSON} JSON array of metadata about documents to download
 **/
function setFromRniJson(rniJson, study, exchangeClient, activity) {
    // Set the scalar data
    var name = rniJson.name;
    if(name == null) {
        throw new Error("Short title not set for RNI");
    }
    setAttributeAndChangeCheck(this, name, "name", activity, false);
    this.setQualifiedAttribute("resourceContainer.name", name);
    setAttributeAndChangeCheck(this, rniJson.dateOfAwareness, "customAttributes.reportableNewInformation.customAttributes.dateOfAwareness", activity, true);
    setAttributeAndChangeCheck(this, rniJson.description, "customAttributes.reportableNewInformation.customAttributes.descriptionOfProblem", activity, false);
    setAttributeAndChangeCheck(this, rniJson.isIncreasedRiskOrSafetyIssue, "customAttributes.reportableNewInformation.customAttributes.isIncreasedRisk", activity, false);
    setAttributeAndChangeCheck(this, rniJson.requiresProtocolRevision, "customAttributes.reportableNewInformation.customAttributes.requiresProtocolRevision", activity, false);
    setAttributeAndChangeCheck(this, rniJson.requiresConsentFormRevision, "customAttributes.reportableNewInformation.customAttributes.consentRequiresRevision", activity, false);
    this.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.reportedByAsString", rniJson.reportedBy);

    // Set the categories
    setSelectionSetFromJson("_ReportableNewInformationCategory", this, "customAttributes.reportableNewInformation.customAttributes.category", rniJson.categories, "ID", activity);

    // Update the security
    this.updateRNIReadersEditors();

    // Set the documents
    var documentsToDownload = [];
    return downloadDocSet(exchangeClient, study, this, "customAttributes.reportableNewInformation.customAttributes.supportingDocuments", rniJson.supportingDocuments, false, documentsToDownload, this, null, null, null, null, activity);
}

Modify Submit Action Response Activity

The post-processing script of the Submit Action Response activity should be modified to upload the reportable new information submission.

Submit Action Response Activity Post-Processing Script Snippet Example

// If RNI is external then upload action response to Exchange
var relatedStudies = targetEntity.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.relatedStudies");
if(relatedStudies != null){
    var relatedStudiesElements = relatedStudies.elements;
    if(relatedStudiesElements.count == 1){
        var isMSS = relatedStudiesElements.item(1).getQualifiedAttribute("customAttributes.isMSS");
        if(isMSS == null){
            throw new Error(-1, "Is MSS not set");
        }
        var isExternal = relatedStudiesElements.item(1).getQualifiedAttribute("customAttributes.externalIRBInvolved");
        if(isExternal == null){
            throw new Error(-1, "Is external not set");
        }
        if(isMSS == true && isExternal == true){
            targetEntity.uploadToExchange(activity);
        }
    }
}

Technical notes about this script snippet example:

  • The reportable new information submission is uploaded to the IRB Exchange if the related submission is an external study downloaded from the IRB Exchange.
  • The _IRBSubmission.uploadToExchange method is called to upload the reportable new information submission to the IRB Exchange. For more information, see the Uploading Submissions tutorial.

Create the Submit Action Response (Admin) Activity

We need a separate activity for Submit Action Response that can be called from a script.

This activity should have execute security open to all Registered Users and have Action Required as the valid state.

Parse Action Responses

_IRBSubmission.setFromRniActionResponseJson Method Example

/** Takes JSON from the IRB Exchange for an RNI action response and sets the data onto the appropriate external RNI.
 *
 * @param mss (_IRBSubmission) The related study
 * @param rniJson (JSON) The RNI JSON downloaded from the IRB Exchange
 * @param exchangeClient (IrbExchange) Handle to the etype to run operations on against the Exchange
 * @param sch (Scripting Context Helper) Needed for logging the activity
 * @param documentsToDownload (JSON) JSON array of metadata about documents to download
 **/
function setFromRniActionResponseJson(mss, rniJson, exchangeClient, sch, documentsToDownload) {
    var lastActionResponseId = this.getQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.lastActionResponseID");
    var stateId = this.getQualifiedAttribute("status.ID");
    if(lastActionResponseId != rniJson.actionResponseId && stateId == "Action Required") {
        var submitActionResponseActivity = ActivityType.getActivityType("_IRBSubmission_SubmitActionResponseAdmin", "_IRBSubmission");
        var activityInstance = this.logActivity(sch, submitActionResponseActivity, Person.getCurrentUser());
        activityInstance.notesAsStr = rniJson.actionResponseNotes;
        this.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.lastActionResponseId", rniJson.actionResponseId);
        documentsToDownload = downloadDocSet(exchangeClient, mss, activityInstance, "documents", rniJson.actionResponseDocuments, false, documentsToDownload, this, null, null, null, null, null);
    }
    return documentsToDownload;
}

Technical notes about this method example:

  • Attribute customAttributes.reportableNewInformation.customAttributes.lastActionResponseID and JSON element actionResponseId are used to ensure that each action response is only downloaded once.
  • The Submit Action Response (Admin) activity is executed to record the action response in the activity history on the sIRB side reportable new information submission.

Pre-Submission -> Pending sIRB Review State Transition

The post-processing script needs to be modified to upload the reportable new information submission to the IRB Exchange.

Pre-Submission -> Pending sIRB Review State Transition Script Snippet Example

// Set the flag for external RNI review and upload to exchange
targetEntity.setQualifiedAttribute("customAttributes.reportableNewInformation.customAttributes.wasReviewedExternally", true);
targetEntity.uploadToExchange(null);
Back to top © 2017 Huron Consulting Group Inc. and affiliates.
Use and distribution prohibited except through written agreement with Huron. Trademarks used in this website are registered or unregistered trademarks of Huron or its licensors.