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
- Adding a method to create JSON representing the study's data.
- Adding a method to create the local site for an external study downloaded from the IRB Exchange.
- Adding a method to parse JSON representing a study into data on the study.
- Adding a method to create an external study that has been downloaded from the IRB Exchange.
- Modifying the Edit Pre-Review activity to upload updates to the IRB Exchange.
- Modifying the Submit activity to upload to the IRB Exchange.
- 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 totrue
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 totrue
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);
}