IRB Exchange

Show / Hide Table of Contents

Studies

Operations on submissions with the IRB Exchange start with studies. Specifically, only multi-site studies where the study's IRB will oversee participating sites are eligible for upload to the IRB Exchange.

What's Involved

  1. Adding a method to create JSON representing the study's data.
  2. Adding a method to create the local site for an external study downloaded from the IRB Exchange.
  3. Adding a method to parse JSON representing a study into data on the study.
  4. Adding a method to create an external study that has been downloaded from the IRB Exchange.
  5. Modifying the Edit Pre-Review activity to upload updates to the IRB Exchange.
  6. Modifying the Submit activity to upload to the IRB Exchange.
  7. Modifying the Pre-Review -> Pre-Review Completed state transition to upload updates to the IRB Exchange.

Create JSON for the Study

_IRBSubmission.toMssJson Method Example

/** Converts the relevant data for a multi-site study into JSON for upload to the IRB Exchange.
 *
 * @param exchangeClient (IrbExchange) Handle to the Exchange client
 *
 * @returns string - stringified JSON representation of the study data
 */
function toMssJson(exchangeClient) {
    // Set most of study level data
    var jsonObj = {};
    jsonObj.poRef =                     this + "";
    jsonObj.name =                      this.getQualifiedAttribute("name");
    jsonObj.title =                     this.getQualifiedAttribute("customAttributes.studyTeamDescription");
    jsonObj.description =               this.getQualifiedAttribute("description");
    jsonObj.isDrugInvolved =            this.getQualifiedAttribute("customAttributes.drugInvolved");
    jsonObj.isDeviceInvolved =          this.getQualifiedAttribute("customAttributes.deviceInvolved");
    jsonObj.isStudyUnderInd =           this.getQualifiedAttribute("customAttributes.isStudyUnderIND");
    jsonObj.deviceExemption =           this.getQualifiedAttribute("customAttributes.deviceType.customAttributes.name");
    jsonObj.status =                    this.getQualifiedAttribute("status.ID");
    jsonObj.lastDayOfApproval =         this.getQualifiedAttribute("customAttributes.dateEndofApproval");
    jsonObj.studyId =                   this.getQualifiedAttribute("ID");
    jsonObj.approvalDate =              this.getQualifiedAttribute("customAttributes.dateApproved");
    jsonObj.preReviewRiskLevel =        this.getQualifiedAttribute("customAttributes.currentReviewInformation.customAttributes.riskLevel.customAttributes.Name");
    jsonObj.preReviewMissingMaterials = this.getQualifiedAttribute("customAttributes.currentReviewInformation.customAttributes.missingMaterials");
    var latestPreReview = null;
    var reviews = this.getQualifiedAttribute("customAttributes.reviews");
    if(reviews != null) {
        var preReviews = reviews.query("customAttributes.reviewType.ID = 'preReview'").sort("dateModified", 106, 0).elements();
        if (preReviews.count() > 0) {
            latestPreReview = preReviews.item(1);
            jsonObj.preReviewNotes = latestPreReview.getQualifiedAttribute("customAttributes.notes");
        }
    }
    jsonObj.initialEffectiveDate =      this.getQualifiedAttribute("customAttributes.dateInitialEffective");
    jsonObj.effectiveDate =             this.getQualifiedAttribute("customAttributes.dateEffective");
    jsonObj.currentCommonRule =         this.getQualifiedAttribute("customAttributes.currentReviewInformation.customAttributes.commonRule.ID");
    jsonObj.usesCombinedCommonRule =    this.getQualifiedAttribute("customAttributes.currentReviewInformation.customAttributes.usesCombinedCommonRule");
    jsonObj.commonRuleLabel =           this.getFullCommonRuleString();

    // Set PI
    var piObj = {};
    piObj.firstName =            this.getQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember.firstName");
    piObj.lastName =             this.getQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember.lastName");
    piObj.email =                this.getQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember.contactInformation.emailPreferred.emailAddress");
    piObj.hasFinancialInterest = this.getQualifiedAttribute("customAttributes.investigator.customAttributes.hasFinancialInterest");
    jsonObj.principalInvestigator = piObj;

    // Set PI proxy
    var piProxies = this.getQualifiedAttribute("customAttributes.piProxiesPerson");
    if (piProxies != null) {
        var piProxiesObj = [];
        piProxies = piProxies.elements();
        for(var i = 1; i <= piProxies.count; i++) {
            var piProxyObj = {};
            var piProxy = piProxies.item(i);
            piProxyObj.firstName = piProxy.firstName;
            piProxyObj.lastName = piProxy.lastName;
            piProxyObj.email = piProxy.getQualifiedAttribute("contactInformation.emailPreferred.emailAddress");
            piProxiesObj.push(piProxyObj);
        }
        jsonObj.piProxies = piProxiesObj;
    }

    // Set primary contact
    var primaryContact = this.getQualifiedAttribute("customAttributes.primaryContact.customAttributes.studyTeamMember");
    if(primaryContact != null) {
        var primaryContactObj = {};
        primaryContactObj.firstName = primaryContact.getQualifiedAttribute("firstName");
        primaryContactObj.lastName = primaryContact.getQualifiedAttribute("lastName");
        primaryContactObj.email = primaryContact.getQualifiedAttribute("contactInformation.emailPreferred.emailAddress");
        jsonObj.primaryContact = primaryContactObj;
    }

    // Funding sources
    var jsonDataMap = [];
    jsonDataMap.push({"jsonName":"name",            "attrPath":"customAttributes.organization.name"});
    jsonDataMap.push({"jsonName":"sponsorId",       "attrPath":"customAttributes.fundingSourceID"});
    jsonDataMap.push({"jsonName":"grantsOfficeId",  "attrPath":"customAttributes.grantOfficeID"});
    jsonDataMap.push({"jsonName":"documents",       "attrPath":"customAttributes.attachments",      "isDocs":"true"});
    jsonObj.fundingSources = toEsetJson(this, "customAttributes.fundingSources", jsonDataMap);

    // Drugs
    jsonDataMap = [];
    jsonDataMap.push({"jsonName":"brandName",   "attrPath":"customAttributes.drug.customAttributes.brandName"});
    jsonDataMap.push({"jsonName":"genericName", "attrPath":"customAttributes.drug.customAttributes.genericName"});
    jsonDataMap.push({"jsonName":"documents",   "attrPath":"customAttributes.drugAttachments",                  "isDocs":"true"});
    jsonObj.drugs = toEsetJson(this, "customAttributes.drugs", jsonDataMap);

    // INDs
    jsonDataMap = [];
    jsonDataMap.push({"jsonName":"number", "attrPath":"customAttributes.INDNumber"});
    jsonDataMap.push({"jsonName":"holder", "attrPath":"customAttributes.INDHolderOther", "altPath":"customAttributes.INDHolder.customAttributes.name"});
    jsonObj.investigationalNewDrugs = toEsetJson(this, "customAttributes.inds", jsonDataMap);

    // Devices
    jsonDataMap = [];
    jsonDataMap.push({"jsonName":"name",                    "attrPath":"customAttributes.device.customAttributes.name"});
    jsonDataMap.push({"jsonName":"isHumanitarainUseDevice", "attrPath":"customAttributes.device.customAttributes.hud"});
    jsonDataMap.push({"jsonName":"documents",               "attrPath":"customAttributes.deviceAttachments",            "isDocs":"true"});
    jsonObj.devices = toEsetJson(this, "customAttributes.devices", jsonDataMap);

    // IDEs
    jsonDataMap = [];
    jsonDataMap.push({"jsonName":"number", "attrPath":"customAttributes.IDENumber"});
    jsonDataMap.push({"jsonName":"holder", "attrPath":"customAttributes.IDEHolderOther", "altPath":"customAttributes.IDEHolder.customAttributes.name"});
    jsonObj.investigationalDeviceExemptions = toEsetJson(this, "customAttributes.ides", jsonDataMap);

    // Document sets on study
    jsonObj.protocolDocuments =                getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.irbProtocolAttachments"));
    jsonObj.drugAttachments =                  getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.drugAttachments"));
    jsonObj.deviceAttachments =                getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.deviceAttachment"));
    jsonObj.consentFormTemplates =             getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.recruitmentDetails.customAttributes.consentFormTemplates"));
    jsonObj.recruitmentMaterialTemplates =     getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.recruitmentDetails.customAttributes.recruitmentTemplates"));
    jsonObj.attachments =                      getDocSetPoRefs(this.getQualifiedAttribute("customAttributes.studySupportingDocuments"));
    if(latestPreReview != null) {
        jsonObj.preReviewSupportingDocuments = getDocSetPoRefs(latestPreReview.getQualifiedAttribute("customAttributes.supportingDocuments"));
    }

    // Correspondence letter
    var correspondenceLetter = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter");
    if(correspondenceLetter != null) {
        var correspondenceLetterObj = {};
        correspondenceLetterObj.attachmentPoRef = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter") + "";
        correspondenceLetterObj.category = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.category.ID");
        correspondenceLetterObj.draftPoRef = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.draftVersion") + "";
        correspondenceLetterObj.draftVersion = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.draftVersion.version");
        var finalVersion = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.finalVersion");
        if(finalVersion != null) {
            correspondenceLetterObj.category = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.category.ID");
            correspondenceLetterObj.finalPoRef = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.finalVersion") + "";
            correspondenceLetterObj.finalVersion = this.getQualifiedAttribute("customAttributes.irbCorrespondenceLetter.customAttributes.finalVersion.version");
        }
        jsonObj.correspondenceLetter = correspondenceLetterObj;
    }

    // Selection sets
    jsonObj.preReviewRegulatoryOversight =             getSelectionSetIds(this, "customAttributes.currentReviewInformation.customAttributes.agencyOversight", "ID");
    jsonObj.preReviewSpecialDeterminationsAndWaivers = getSelectionSetIds(this, "customAttributes.currentReviewInformation.customAttributes.specialDeterminationAndWaivers", "ID");
    jsonObj.preReviewResearchType =                    getSelectionSetIds(this, "customAttributes.currentReviewInformation.customAttributes.researchType", "customAttributes.name");
    jsonObj.preReviewTrackingFlags =                   getSelectionSetIds(this, "customAttributes.currentReviewInformation.customAttributes.trackingFlags", "customAttributes.name");
    jsonObj.preReviewPediatricRiskLevels =             getSelectionSetIds(this, "customAttributes.currentReviewInformation.customAttributes.pediatricRiskLevels", "customAttributes.code");

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

Technical notes about this method example:

  • For data entry sets, the method creates a separate JSON structure to specify metadata about the set. This is passed to calls to the _IRBSubmission.toEsetJson method. See the Data Entry Sets tutorial for more information.
  • JSON for the document sets is retrieved via calls to the _IRBSubmission.getDocSetPoRefs method. See the Documents tutorial for more information.
  • JSON for selection sets is retrieved via calls to the _IRBSubmission.getSelectionSetIds method. See the Selections tutorial for more information.

Parse Study JSON

_IRBSubmission.setFromMssJson Method Example

/** Takes JSON from the IRB Exchange for a multi-site study and sets the data onto the appropriate external study.
    @param studyJson (JSON) JSON of the study containing its data
    @param exchangeClient (IrbExchange) Handle to the etype to run operations on against the Exchange
    @param organization (Company) The sIRB institution
    @param organizationName (string) Name of the sIRB institution
    @param isSubscribedToProfileData (Boolean) Flag indicating whether this store subscribes to ProfileData publication in CPIP
    @param activity (Activity) The Update from IRB Exchange or Update from IRB Exchange (Admin) activity that triggered the call here, or null if initial download
*/
function setFromMssJson(studyJson, exchangeClient, organization, organizationName, isSubscribedToProfileData, activity) {
    // Set the scalar data
    var studyName = studyJson.name;
    if(studyName == null) {
        throw new Error("Short title not set for study");
    }
    setAttributeAndChangeCheck(this, studyName, "name", activity, false);
    this.setQualifiedAttribute("resourceContainer.name", studyName);
    if(organization == null && organizationName == null) {
        organization = this.company;
    }
    var leadPi = getMatchedPersonFromExchangeData(studyJson.principalInvestigator.email, studyJson.principalInvestigator.firstName, studyJson.principalInvestigator.lastName, organization, organizationName, isSubscribedToProfileData, this, "customAttributes.leadInvestigator.customAttributes.studyTeamMember");
    if (leadPi) {
        setAttributeAndChangeCheck(this, leadPi, "customAttributes.leadInvestigator.customAttributes.studyTeamMember", activity, false);
    }
    setAttributeAndChangeCheck(this, studyJson.title, "customAttributes.studyTeamDescription", activity, false);
    setAttributeAndChangeCheck(this, studyJson.description, "description", activity, false);
    setAttributeAndChangeCheck(this, studyJson.principalInvestigator.hasFinancialInterest, "customAttributes.leadInvestigator.customAttributes.hasFinancialInterest", activity, false);
    setAttributeAndChangeCheck(this, studyJson.isDrugInvolved, "customAttributes.drugInvolved", activity, false);
    setAttributeAndChangeCheck(this, studyJson.isDeviceInvolved, "customAttributes.deviceInvolved", activity, false);
    setAttributeAndChangeCheck(this, studyJson.isStudyUnderInd, "customAttributes.isStudyUnderIND", activity, false);
    setAttributeAndChangeCheck(this, studyJson.status, "customAttributes.externalStudyStatus", activity, false);
    setAttributeAndChangeCheck(this, studyJson.lastDayOfApproval, "customAttributes.dateEndofApproval", activity, true);
    this.setQualifiedAttribute("customAttributes.cededStudyID", studyJson.studyId);
    setSelectionSetFromJson("Person", this, "customAttributes.piProxiesPersonMSS", studyJson.piProxies, "contactInformation.emailPreferred.emailAddress", activity);

    // Set the device type
    if(studyJson.deviceExemption != null) {
        var deviceType = getEntityForAttribute(studyJson, "customAttributes.name = '" + studyJson.deviceExemption.replace("'", "''") + "'", "_deviceType", null, null);
        setAttributeAndChangeCheck(this, deviceType, "customAttributes.deviceType", activity, false);
    }

    // Set the eSet data
    var docsToDownloadJson = [];
    docsToDownloadJson = updateEsetFromExchange(this, "customAttributes.fundingSources", studyJson.fundingSources, "_FundingSource", exchangeClient, docsToDownloadJson, this, activity);
    docsToDownloadJson = updateEsetFromExchange(this, "customAttributes.drugs", studyJson.drugs, "_Drug", exchangeClient, docsToDownloadJson, this, activity);
    docsToDownloadJson = updateEsetFromExchange(this, "customAttributes.inds", studyJson.investigationalNewDrugs, "_INDInformation", exchangeClient, docsToDownloadJson, this, activity);
    docsToDownloadJson = updateEsetFromExchange(this, "customAttributes.devices", studyJson.devices, "_Device", exchangeClient, docsToDownloadJson, this, activity);
    docsToDownloadJson = updateEsetFromExchange(this, "customAttributes.ides", studyJson.investigationalDeviceExemptions, "_IDEInformation", exchangeClient, docsToDownloadJson, this, activity);

    // Document sets on study
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.irbProtocolAttachments", studyJson.protocolDocuments, true, docsToDownloadJson, this, "Protocol Documents", null, null, null, activity);
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.drugAttachments", studyJson.drugAttachments, true, docsToDownloadJson, this, "Drug Attachments", null, null, null, activity);
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.deviceAttachment", studyJson.deviceAttachments, true, docsToDownloadJson, this, "Device Attachments", null, null, null, activity);
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.recruitmentDetails.customAttributes.consentFormTemplates", studyJson.consentFormTemplates, true, docsToDownloadJson, this, "Recruitment Details.Consent Form Templates", null, null, null, activity);
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.recruitmentDetails.customAttributes.recruitmentTemplates", studyJson.recruitmentMaterialTemplates, true, docsToDownloadJson, this, "Recruitment Details.Recruitment Templates", null, null, null, activity);
    docsToDownloadJson = downloadDocSet(exchangeClient, this, this, "customAttributes.studySupportingDocuments", studyJson.attachments, true, docsToDownloadJson, this, "Study Supporting Documents", null, null, null, activity);

    // Correspondence letter
    if(studyJson.correspondenceLetter != null) {
        var correspondenceLetter = this.getQualifiedAttribute("customAttributes.approvalLetter");
        var doc;
        var currentDate = new Date();

        if(correspondenceLetter == null) {
            // Not currently set locally, so create it
            doc = Document.createEntity();
            var modifier = ApplicationEntity.getResultSet("Modifier").query("ID = 'Document'").elements();
            doc.setQualifiedAttribute("modifiers", modifier.item(1), "add");
            var currentUser = Person.getCurrentUser();
            doc.setQualifiedAttribute("owner", currentUser);
            this.setQualifiedAttribute("customAttributes.approvalLetter.customAttributes.draftVersion", doc);
            correspondenceLetter = this.getQualifiedAttribute("customAttributes.approvalLetter");
            doc.setQualifiedAttribute("dateCreated", currentDate);
            correspondenceLetter.setQualifiedAttribute("dateCreated", currentDate);
            correspondenceLetter.setQualifiedAttribute("owningEntity", this);
        } else {
            // Currently set, get the draft doc
            doc = correspondenceLetter.getQualifiedAttribute("customAttributes.draftVersion");
        }

        // Stuff the document download info into the JSON for doc download control on workspace
        var correspondenceLetterJson = {};
        correspondenceLetterJson.document = doc + "";
        correspondenceLetterJson.exchangeRef = studyJson.correspondenceLetter.draftExchangeRef;
        docsToDownloadJson.push(correspondenceLetterJson);

        // Set draft doc values and get change detection values for them
        var hasVersionChanged = setAttributeAndChangeCheck(doc, studyJson.correspondenceLetter.draftVersion, "version", activity, false);
        var hasNameChanged = setAttributeAndChangeCheck(doc, studyJson.correspondenceLetter.draftName, "name", activity, false);

        // If draft doc values changed, update date modified
        if(hasVersionChanged == true || hasNameChanged == true) {
            doc.setQualifiedAttribute("dateModified", currentDate);
        }

        // Set category if provided
        if(studyJson.correspondenceLetter.category != null) {
            var letterCategory = getEntityForAttribute(studyJson.correspondenceLetter, "ID = '" + studyJson.correspondenceLetter.category.replace("'", "''") + "'", "_AttachmentCategory", null, null);
            correspondenceLetter.setQualifiedAttribute("customAttributes.category", letterCategory);
        }

        // Handle final version if set
        if(studyJson.correspondenceLetter.finalExchangeRef) {
            doc = correspondenceLetter.getQualifiedAttribute("customAttributes.finalVersion");

            // Final version isn't set, so create it
            if(doc == null) {
                doc = Document.createEntity();
                doc.setQualifiedAttribute("modifiers", modifier.item(1), "add");
                doc.setQualifiedAttribute("owner", currentUser);
                correspondenceLetter.setQualifiedAttribute("customAttributes.finalVersion", doc);
                doc.setQualifiedAttribute("dateCreated", currentDate);
            }

            // Stuff the final document download info into the JSON for doc download control on workspace
            correspondenceLetterJson = {};
            correspondenceLetterJson.document = doc + "";
            correspondenceLetterJson.exchangeRef = studyJson.correspondenceLetter.finalExchangeRef;
            docsToDownloadJson.push(correspondenceLetterJson);

            // Set final doc values and get change detection values for them
            hasVersionChanged = setAttributeAndChangeCheck(doc, studyJson.correspondenceLetter.finalVersion, "version", activity, false);
            hasNameChanged = setAttributeAndChangeCheck(doc, studyJson.correspondenceLetter.finalName, "name", activity, false);

            // If final doc values changed, update date modified
            if(hasVersionChanged == true || hasNameChanged == true) {
                doc.setQualifiedAttribute("dateModified", currentDate);
            }
        }
    }

    // If the organization on the IP isn't set, then lookup and set it
    var ip = this.getQualifiedAttribute("customAttributes.mSSPSiteInstitutionalProfile");
    var organization = ip.getQualifiedAttribute("customAttributes.institution");
    if(organization.name != studyJson.owner.name) {
        var matchingOrgs = ApplicationEntity.getResultSet("Company").query("name like '" + studyJson.owner.name + "'").elements();
        if(matchingOrgs.count() == 1) {
            organization = matchingOrgs.item(1);
            ip.setQualifiedAttribute("customAttributes.institution", organization);
            IrbExchangeReference.LinkExchangeIdToPoRef(studyJson.owner.exchangeRef, organization + "", null, exchangeClient.GetEndpoint() + "", true, false, true, true);
        }
    }

    // Get the sIRB review entity
    var reviews = this.getQualifiedAttribute("customAttributes.reviews");
    if(reviews == null) {
        reviews = _ClickIRBReviewChecklist.createEntitySet();
        this.setQualifiedAttribute("customAttributes.reviews", reviews);
    }
    var sirbReview;
    var incompleteSirbReviews = reviews.query("customAttributes.reviewType.ID = 'sIRBReview' and customAttributes.isCompleted = false").sort("dateModified", 106, 0).elements();
    var sirbReviewType = getResultSet("_ClickReviewType").query("ID = 'sIRBReview'").elements().item(1);
    if(incompleteSirbReviews.count() > 0) {
        sirbReview = incompleteSirbReviews.item(1);
    } else {
        sirbReview = _ClickIRBReviewChecklist.createEntity();
        sirbReview.setQualifiedAttribute("customAttributes.reviewType", sirbReviewType);
        sirbReview.setQualifiedAttribute("owningEntity", this);
        reviews.addElement(sirbReview);

        // Copy info from the last completed sIRB review to this one so we have a complete record for display
        var completeSirbReviews = reviews.query("customAttributes.reviewType.ID = 'sIRBReview' and customAttributes.isCompleted = true").sort("dateModified", 106, 0).elements();
        if(completeSirbReviews.count() > 0) {
            _ClickIRBReviewChecklist.copyReviewInformation(completeSirbReviews.item(1), sirbReview);
        }

        sirbReview.setQualifiedAttribute("customAttributes.isCompleted", false);
    }

    // sIRB review scalars
    setAttributeAndChangeCheck(sirbReview, studyJson.preReviewMissingMaterials, "customAttributes.missingMaterials", activity, false);
    setAttributeAndChangeCheck(sirbReview, studyJson.preReviewNotes, "customAttributes.notes", activity, false);
    setAttributeAndChangeCheck(sirbReview, studyJson.approvalDate, "customAttributes.dateApproved", activity, true);
    setAttributeAndChangeCheck(sirbReview, studyJson.effectiveDate, "customAttributes.dateEffective", activity, true);
    setAttributeAndChangeCheck(sirbReview, studyJson.lastDayOfApproval, "customAttributes.dateExpiration", activity, true);
    sirbReview.setQualifiedAttribute("dateModified", new Date());

    // Set common rule
    if(studyJson.currentCommonRule != null) {
        var commonRule = getEntityForAttribute(studyJson, "ID = '" + studyJson.currentCommonRule.replace("'", "''") + "'", "_ClickIRBCommonRule", null, null);
        setAttributeAndChangeCheck(sirbReview, commonRule, "customAttributes.commonRule", activity, false);
        var usesCombinedCommonRule = studyJson.usesCombinedCommonRule;
        sirbReview.setQualifiedAttribute("customAttributes.usesCombinedCommonRule",usesCombinedCommonRule);

        // Set initial common rule if not set
        var initialCommonRule = this.getQualifiedAttribute("customAttributes.initialCommonRule");
        if(initialCommonRule == null) {
            this.setQualifiedAttribute("customAttributes.initialCommonRule", commonRule);
            this.setQualifiedAttribute("customAttributes.usesCombinedCommonRuleInitial", usesCombinedCommonRule);
        }
    }
    // sIRB site review dates
    if(studyJson.siteReviewData != null) {
        this.setQualifiedAttribute("customAttributes.dateApproved", studyJson.siteReviewData.approvalDate);
        this.setQualifiedAttribute("customAttributes.dateInitialEffective", studyJson.siteReviewData.initialEffectiveDate);
        this.setQualifiedAttribute("customAttributes.dateEffective", studyJson.siteReviewData.effectiveDate);
        this.setQualifiedAttribute("customAttributes.dateEndofSiteApproval", studyJson.siteReviewData.lastDayOfApproval);
        if(studyJson.siteReviewData.determination != undefined && studyJson.siteReviewData.determination != null) {
            var determination = getEntityForAttribute(studyJson, "customAttributes.name = '" + studyJson.siteReviewData.determination.replace("'", "''") + "'", "_IRBDetermination", null, null);
            setAttributeAndChangeCheck(sirbReview, determination, "customAttributes.irbDetermination", activity, false);
        }
        setAttributeAndChangeCheck(sirbReview, studyJson.siteReviewData.approvalDate, "customAttributes.dateSiteApproved", activity, true);
        setAttributeAndChangeCheck(sirbReview, studyJson.siteReviewData.effectiveDate, "customAttributes.dateSiteEffective", activity, true);
        if(studyJson.siteReviewData.lastDayOfApproval != undefined) {
            sirbReview.setQualifiedAttribute("customAttributes.dateSiteExpiration", studyJson.siteReviewData.lastDayOfApproval);
        }
        setAttributeAndChangeCheck(sirbReview, studyJson.siteReviewData.requiredModifications, "customAttributes.modificationsRequiredNotes", activity, false);
    }

    // sIRB review risk level
    if(studyJson.preReviewRiskLevel != null) {
        var riskLevel = getEntityForAttribute(studyJson, "customAttributes.name = '" + studyJson.preReviewRiskLevel.replace("'", "''") + "'", "_IRBRiskLevel", null, null);
        setAttributeAndChangeCheck(sirbReview, riskLevel, "customAttributes.riskLevel", activity, false);
    }

    // sIRB review documents
    docsToDownloadJson = downloadDocSet(exchangeClient, this, sirbReview, "customAttributes.supportingDocuments", studyJson.preReviewSupportingDocuments, false, docsToDownloadJson, this, null, null, null, null, activity);

    // sIRB review selection sets
    setSelectionSetFromJson("_RegulatoryOversight", sirbReview, "customAttributes.agencyOversight", studyJson.preReviewRegulatoryOversight, "ID", activity);
    setSelectionSetFromJson("_SpecialDeterminationsAndWaivers", sirbReview, "customAttributes.specialDeterminationAndWaivers", studyJson.preReviewSpecialDeterminationsAndWaivers, "ID", activity);
    setSelectionSetFromJson("_researchType", sirbReview, "customAttributes.researchType", studyJson.preReviewResearchType, "customAttributes.name", activity);
    setSelectionSetFromJson("_IRBTrackingFlag", sirbReview, "customAttributes.trackingFlags", studyJson.preReviewTrackingFlags, "customAttributes.name", activity);
    setSelectionSetFromJson("_ClickIRBPediatricRiskLevel", sirbReview, "customAttributes.pediatricRiskLevels", studyJson.preReviewPediatricRiskLevels, "customAttributes.code", activity);

    // Copy historical sIRB review data we just set to the current review entity
    var currentReviewInfo = this.getQualifiedAttribute("customAttributes.currentReviewInformation");
    if(currentReviewInfo == null) {
        currentReviewInfo = _ClickIRBReviewChecklist.createEntity();
        currentReviewInfo.setQualifiedAttribute("customAttributes.reviewType", sirbReviewType);
        this.setQualifiedAttribute("customAttributes.currentReviewInformation", currentReviewInfo);
    }
    _ClickIRBReviewChecklist.copyReviewInformation(sirbReview, currentReviewInfo);

    // Set the common rule on the pSite and any mods it may have
    this.setCommonRuleOnSitesAndFollowOns();

    return docsToDownloadJson;
}

Technical notes about this method example:

  • This method sets data downloaded from the IRB Exchange on external studies both for initial download and updates.
  • Persons are matched using the _IRBSubmission.getMatchedPersonFromExchangeData method. See the Selections tutorial for more information.
  • The customAttributes.externalStudyStatus attribute is set to the string value of the state the study is in on the sIRB store or system.
  • The customAttributes.cededStudyID attribute is set to the string value of the ID of the study in the sIRB store or system.
  • Handling for the correspondence letter is an example of the data that needs to be set on newly created _Attachment and Document entities.
  • Review data is set into the latest sIRB review entity.

Create External Study

_IRBSubmission.createExternalStudyFromExchange Method Example

/** Creates an external study when downloading a study from the IRB Exchange.
 @param studyJson (JSON) The study's data
 @param exchangeClient (IrbExchange) Entity with methods to run on the IRB Exchange
 @return returnObj (JSON) - The new external study
 **/
function createExternalStudyFromExchange(studyJson, exchangeClient) {
    var sch = ShadowSCH.getRealOrShadowSCH();
    var currentUser = Person.getCurrentUser();
    var submissionType = getResultSet("_SubmissionType").query("ID = 'STUDY'").elements.item(1);
    var sIrbOrganizationId = studyJson.owner.exchangeRef;
    if(sIrbOrganizationId == null) {
        throw new Error("sIRB Organization ID is unexpectedly null for study");
    }

    // Create the external study and fill in some basic info
    var study = _IRBSubmission.create("tempProjName",submissionType,null,null); //project name will be changed by method caller
    study.setQualifiedAttribute("customAttributes.isMSS", true);
    study.setQualifiedAttribute("customAttributes.externalIRBInvolved", true);
    study.setQualifiedAttribute("customAttributes.parentStudy", study);
    study.setQualifiedAttribute("customAttributes.exchangeInfo.customAttributes.hasPSiteBeenApproved", false);

    // Get the sIRB's IP
    var matchingOrg = IrbExchangeReference.GetPoRef(sIrbOrganizationId, null, exchangeClient.GetEndpoint() + "");
    var matchingIpsCount = 0;
    if(matchingOrg != null) {
        var matchingIps = ApplicationEntity.getResultSet("_ClickIRBInstitutionalProfile").query("customAttributes.institution = " + matchingOrg).elements();
        matchingIpsCount = matchingIps.count();
    }
    var ip;
    var isSubscribedToProfileData = ClickIntegrationUtils.IsStoreSubscribedToPublication("ProfileData");
    var organizationName = studyJson.owner.name;
    var organization;
    if(matchingIpsCount == 0) {
        // Create IP
        ip = _ClickIRBInstitutionalProfile.createEntity();
        var matchingOrgs = ApplicationEntity.getResultSet("Company").query("name like '" + organizationName + "'").elements();
        if(matchingOrgs.count() == 0) {
            // Create organization
            if(isSubscribedToProfileData == true) {
                var createOrgEventArgs = {};
                createOrgEventArgs.type = "Company";
                createOrgEventArgs.companyName = organizationName;
                createOrgEventArgs.submissionPoRef = study + "";
                study.triggerEvent("ClickIRBSubmissionCreateProfileData", JSON.stringify(createOrgEventArgs, null, null));
                var huronOrg = ApplicationEntity.getResultSet("Company").query("name = 'Huron Consulting, Inc.'").elements();
                if(huronOrg.count() > 0) {
                    organization = huronOrg.item(1);
                } else {
                    var orgs = ApplicationEntity.getResultSet("Company").elements();
                    if(orgs.count() > 0) {
                        organization = orgs.item(1);
                    } else {
                        throw new Error("No organizations exist");
                    }
                }
            } else {
                organization = Company.createEntity();
                organization.ID = organization.getID();
                organization.setQualifiedAttribute("name", organizationName);
            }
        } else {
            organization = matchingOrgs.item(1);
        }
        ip.setQualifiedAttribute("customAttributes.institution", organization);
        IrbExchangeReference.LinkExchangeIdToPoRef(sIrbOrganizationId, organization + "", null, exchangeClient.GetEndpoint() + "", true, false, false, true);
        ip.setQualifiedAttribute("customAttributes.isConnectedToIRBExchange", true);
        ip.setQualifiedAttribute("customAttributes.isEligibleSIRB", true);
        ip.setQualifiedAttribute("customAttributes.isActive", true);
    } else {
        ip = matchingIps.item(1);
        organization = ip.getQualifiedAttribute("customAttributes.institution");
    }
    study.setQualifiedAttribute("customAttributes.mSSPSiteInstitutionalProfile", ip);

    // Set the company on the study
    study.setQualifiedAttribute("company", organization);

    // Create the workspace
    var matchingIrbPages = ApplicationEntity.getResultSet("Container").query("ID = 'CLICK_IRB_HOME'").elements();
    var matchingIrbPagesCount = matchingIrbPages.count();
    if(matchingIrbPagesCount != 1) {
        throw new Error("Unexpected count of Container entities matching ID CLICK_IRB_HOME; should be 1, but got " + matchingIrbPagesCount);
    }
    var irbPage = matchingIrbPages.item(1);
    study.createWorkspace(irbPage, study.setWorkspaceTemplate());

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

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

    // Set the flag to indicate this site can download Exchange updates for study and sIRB site review dates
    study.setQualifiedAttribute("customAttributes.canDownloadExchangeUpdates", true);

    // Fill in rest of study SmartForm data
    var documentsToDownload;
    if(organization.name == organizationName) {
        documentsToDownload = study.setFromMssJson(studyJson, exchangeClient, organization, null, isSubscribedToProfileData, null);
    } else {
        documentsToDownload = study.setFromMssJson(studyJson, exchangeClient, null, organizationName, isSubscribedToProfileData, null);
    }

    // Set the study type to MSS
    var studyType = getEntityForAttribute(studyJson, "ID = '00000001'", "_ClickIRBStudyType", null, null);
    study.setQualifiedAttribute("customAttributes.studyType", studyType);

    // Get and set the admin office
    var matchingAdminOffices;
    if(studyJson.adminOfficeId != null) {
        matchingAdminOffices = ApplicationEntity.getResultSet("_AdminOffice").query("ID = '" + studyJson.adminOfficeId + "'").elements();
        var matchingAdminOfficesCount = matchingAdminOffices.count();
        if(matchingAdminOfficesCount != 1) {
            throw new Error("Unexpected number of matches for Admin Office with ID " + studyJson.adminOfficeId + "; Count: " + matchingAdminOfficesCount);
        }
    } else {
        throw new Error("Admin Office selection lost for study with exchangeRef " + studyJson.exchangeRef + ".");
    }
    study.setQualifiedAttribute("customAttributes.IRB", matchingAdminOffices.item(1));

    // Set the PI on the site from the data from the Exchange that came with the study
    var pi;
    if(organization.name == organizationName) {
        pi = getMatchedPersonFromExchangeData(studyJson.sitePrincipalInvestigator.email, studyJson.sitePrincipalInvestigator.firstName, studyJson.sitePrincipalInvestigator.lastName, organization, null, isSubscribedToProfileData, study, "customAttributes.investigator.customAttributes.studyTeamMember");
    } else {
        pi = getMatchedPersonFromExchangeData(studyJson.sitePrincipalInvestigator.email, studyJson.sitePrincipalInvestigator.firstName, studyJson.sitePrincipalInvestigator.lastName, null, organizationName, isSubscribedToProfileData, study, "customAttributes.investigator.customAttributes.studyTeamMember");
    }
    if(pi != null) {
        study.setQualifiedAttribute("customAttributes.investigator.customAttributes.studyTeamMember", pi);
    }
    study.updateReadersAndEditors(null);

    // Set site inbox contacts (study staff)
    study.updateContacts("StudyStaff");

    // Log creation in the history
    var createStudyActivity = ActivityType.getActivityType("_IRBSubmission_CreateStudy", "_IRBSubmission");
    createStudyActivity = study.logActivity(sch, createStudyActivity, currentUser);
    createStudyActivity.majorVersion = 0;
    createStudyActivity.minorVersion = 1;
    createStudyActivity.versionDescription = "Initial Download from IRB Exchange";

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

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

Technical notes about this method example:

  • This method contains a lot of the same code as in the _IRBSubmission.onCreate method for standard setup.
  • The customAttributes.isMSS attribute is set to true to denote this is a multi-site study.
  • If the sIRB's institutional profile exists already, then it sets that on the site. Otherwise, it creates the institutional profile, and assigned institution organization if needed. If it needs to create the organization, is integrated using CPIP and doesn't host the ProfileData publication, then it fires a CPIP event to have the organization created on the profile data host.
  • The site is linked to its IRB Exchange counterpart using a method call to IrbExchangeReference.LinkExchangeIdToPoRef.
  • The customAttributes.canDownloadExchangeUpdates attribute is set to true on both the external study and site to signify they can receive updates from the IRB Exchange.
  • The return value is JSON and contains an array of metadata about documents to download from the IRB Exchange along with the study poRef.
  • This method contains an adapation of some of the same code in the _IRBSubmission.onCreate method that handles standard submission setup.

Edit Pre-Review Activity

The Edit Pre-Review activity needs to upload updates to the IRB Exchange, since pre-review data is transferred over the IRB Exchange.

Edit Pre-Review Activity Post-Processing Snippet Example

// If MSS, then upload study to Exchange
var isMSS = targetEntity.getQualifiedAttribute("customAttributes.isMSS");
if (isMSS == true) {
   targetEntity.uploadToExchange(null);
}

Technical notes about this script snippet example:

  • Updates are uploaded if the study is a multi-site study.
  • The _IRBSubmission.uploadToExchange method is called to start the upload process.

Pre-Review -> Pre-Review Completed State Transition

The post-processing script needs to be modified to upload updates to the IRB Exchange.

Pre-Review -> Pre-Review Completed State Transition Post-Processing Script Snippet Example

// If MSS, upload to exchange
var isMSS = targetEntity.getQualifiedAttribute("customAttributes.isMSS");
if(isMSS == 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.