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
- Adding a method to create JSON representing a reportable new information submission.
- Adding two attributes to the Reportable New Information CDT to store reported by string and last action response ID.
- Adding a method to create reportable new information submission on sIRB side.
- Adding a method to parse JSON representing a reportable new information submission and set the data on the submission.
- Modifying the Submit Action Response activity to call a method to upload an action response to the IRB Exchange.
- 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.
- Adding a method to parse JSON representing an action response and record that activity on the reportable new information submission on the sIRB side.
- 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 tofalse
. 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 totrue
. 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 elementactionResponseId
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);