Adds documents_status StudyInfo script. Adds Documents & Approvals workflow spec.
This commit is contained in:
parent
2e601719ad
commit
d91f690388
|
@ -48,7 +48,7 @@ For example:
|
||||||
|
|
||||||
def get_documents(self, study_id, pb_docs):
|
def get_documents(self, study_id, pb_docs):
|
||||||
"""Takes data from the protocol builder, and merges it with data from the IRB Pro Categories spreadsheet to return
|
"""Takes data from the protocol builder, and merges it with data from the IRB Pro Categories spreadsheet to return
|
||||||
pertinant details about the required documents."""
|
pertinent details about the required documents."""
|
||||||
|
|
||||||
doc_dictionary = FileService.get_file_reference_dictionary()
|
doc_dictionary = FileService.get_file_reference_dictionary()
|
||||||
required_docs = {}
|
required_docs = {}
|
||||||
|
|
|
@ -3,6 +3,7 @@ from ldap3.core.exceptions import LDAPSocketOpenError
|
||||||
from crc import session, app
|
from crc import session, app
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
from crc.models.study import StudyModel, StudySchema
|
from crc.models.study import StudyModel, StudySchema
|
||||||
|
from crc.models.workflow import WorkflowStatus
|
||||||
from crc.scripts.script import Script
|
from crc.scripts.script import Script
|
||||||
from crc.services.ldap_service import LdapService
|
from crc.services.ldap_service import LdapService
|
||||||
from crc.services.protocol_builder import ProtocolBuilderService
|
from crc.services.protocol_builder import ProtocolBuilderService
|
||||||
|
@ -14,7 +15,7 @@ class StudyInfo(Script):
|
||||||
|
|
||||||
"""Just your basic class that can pull in data from a few api endpoints and do a basic task."""
|
"""Just your basic class that can pull in data from a few api endpoints and do a basic task."""
|
||||||
pb = ProtocolBuilderService()
|
pb = ProtocolBuilderService()
|
||||||
type_options = ['info', 'investigators', 'details', 'approvals']
|
type_options = ['info', 'investigators', 'details', 'approvals', 'documents_status']
|
||||||
|
|
||||||
def get_description(self):
|
def get_description(self):
|
||||||
return """StudyInfo [TYPE], where TYPE is one of 'info', 'investigators', or 'details'
|
return """StudyInfo [TYPE], where TYPE is one of 'info', 'investigators', or 'details'
|
||||||
|
@ -47,7 +48,27 @@ class StudyInfo(Script):
|
||||||
"NETBADGEID": "dhf8r"
|
"NETBADGEID": "dhf8r"
|
||||||
},
|
},
|
||||||
"details":
|
"details":
|
||||||
{}
|
{},
|
||||||
|
"approvals": {
|
||||||
|
"id": 321,
|
||||||
|
"display_name": "IRB API Details",
|
||||||
|
"name": "irb_api_details",
|
||||||
|
"status": WorkflowStatus.not_started.value,
|
||||||
|
"workflow_spec_id": "irb_api_details",
|
||||||
|
},
|
||||||
|
"documents_status": [
|
||||||
|
{
|
||||||
|
'category1': 'Ancillary Document',
|
||||||
|
'category2': 'CoC Application',
|
||||||
|
'category3': '',
|
||||||
|
'Who Uploads?': 'CRC',
|
||||||
|
'Id': '12',
|
||||||
|
'Name': 'Certificate of Confidentiality Application',
|
||||||
|
'count': 0,
|
||||||
|
'required': False,
|
||||||
|
'code': 'AD_CoCApp'
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.add_data_to_task(task=task, data=data["study"])
|
self.add_data_to_task(task=task, data=data["study"])
|
||||||
|
@ -71,6 +92,9 @@ class StudyInfo(Script):
|
||||||
self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
|
self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
|
||||||
if cmd == 'approvals':
|
if cmd == 'approvals':
|
||||||
self.add_data_to_task(task, {cmd: StudyService().get_approvals(study_id)})
|
self.add_data_to_task(task, {cmd: StudyService().get_approvals(study_id)})
|
||||||
|
if cmd == 'documents_status':
|
||||||
|
self.add_data_to_task(task, {cmd: StudyService().get_documents_status(study_id)})
|
||||||
|
|
||||||
task.data["study"] = study_info
|
task.data["study"] = study_info
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,14 @@ from SpiffWorkflow import WorkflowException
|
||||||
|
|
||||||
from crc import db, session
|
from crc import db, session
|
||||||
from crc.api.common import ApiError
|
from crc.api.common import ApiError
|
||||||
|
from crc.models.file import FileModel
|
||||||
from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStatus
|
from crc.models.protocol_builder import ProtocolBuilderStudy, ProtocolBuilderStatus
|
||||||
from crc.models.stats import WorkflowStatsModel, TaskEventModel
|
from crc.models.stats import WorkflowStatsModel, TaskEventModel
|
||||||
from crc.models.study import StudyModel, Study, Category, WorkflowMetadata
|
from crc.models.study import StudyModel, Study, Category, WorkflowMetadata
|
||||||
from crc.models.workflow import WorkflowSpecCategoryModel, WorkflowModel, WorkflowSpecModel, WorkflowState, \
|
from crc.models.workflow import WorkflowSpecCategoryModel, WorkflowModel, WorkflowSpecModel, WorkflowState, \
|
||||||
WorkflowStatus
|
WorkflowStatus
|
||||||
|
from crc.scripts.documents import Documents
|
||||||
|
from crc.services.file_service import FileService
|
||||||
from crc.services.protocol_builder import ProtocolBuilderService
|
from crc.services.protocol_builder import ProtocolBuilderService
|
||||||
from crc.services.workflow_processor import WorkflowProcessor
|
from crc.services.workflow_processor import WorkflowProcessor
|
||||||
|
|
||||||
|
@ -64,13 +67,13 @@ class StudyService(object):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_approvals(study_id):
|
def get_approvals(study_id):
|
||||||
"""Returns a list of category objects, in the correct order."""
|
"""Returns a list of approval workflows."""
|
||||||
cat = session.query(WorkflowSpecCategoryModel).filter_by(name="approvals").first()
|
cat = session.query(WorkflowSpecCategoryModel).filter_by(name="approvals").first()
|
||||||
specs = session.query(WorkflowSpecModel).filter_by(category_id=cat.id).all()
|
specs = session.query(WorkflowSpecModel).filter_by(category_id=cat.id).all()
|
||||||
spec_ids = [spec.id for spec in specs]
|
spec_ids = [spec.id for spec in specs]
|
||||||
workflows = session.query(WorkflowModel)\
|
workflows = session.query(WorkflowModel) \
|
||||||
.filter(WorkflowModel.study_id == study_id)\
|
.filter(WorkflowModel.study_id == study_id) \
|
||||||
.filter(WorkflowModel.workflow_spec_id.in_(spec_ids))\
|
.filter(WorkflowModel.workflow_spec_id.in_(spec_ids)) \
|
||||||
.all()
|
.all()
|
||||||
|
|
||||||
approvals = []
|
approvals = []
|
||||||
|
@ -80,11 +83,44 @@ class StudyService(object):
|
||||||
'id': workflow.id,
|
'id': workflow.id,
|
||||||
'display_name': workflow.workflow_spec.display_name,
|
'display_name': workflow.workflow_spec.display_name,
|
||||||
'name': workflow.workflow_spec.display_name,
|
'name': workflow.workflow_spec.display_name,
|
||||||
'status': workflow.status,
|
'status': workflow.status.value,
|
||||||
'workflow_spec_id': workflow.workflow_spec_id,
|
'workflow_spec_id': workflow.workflow_spec_id,
|
||||||
})
|
})
|
||||||
return approvals
|
return approvals
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_documents_status(study_id):
|
||||||
|
"""Returns a list of required documents and related workflow status."""
|
||||||
|
doc_service = Documents()
|
||||||
|
|
||||||
|
# Get PB required docs
|
||||||
|
pb_docs = ProtocolBuilderService.get_required_docs(study_id)
|
||||||
|
|
||||||
|
# Get required docs for study
|
||||||
|
study_docs = doc_service.get_documents(study_id=study_id, pb_docs=pb_docs)
|
||||||
|
|
||||||
|
# Container for results
|
||||||
|
documents = []
|
||||||
|
|
||||||
|
# For each required doc, get file(s)
|
||||||
|
for code, doc in study_docs.items():
|
||||||
|
doc['study_id'] = study_id
|
||||||
|
doc['code'] = code
|
||||||
|
doc_files = FileService.get_files(study_id=study_id, irb_doc_code=code)
|
||||||
|
|
||||||
|
# For each file, get associated workflow status
|
||||||
|
for file in doc_files:
|
||||||
|
doc['file_id'] = file.id
|
||||||
|
doc['workflow_id'] = file.workflow_id
|
||||||
|
|
||||||
|
if doc['status'] is None:
|
||||||
|
workflow: WorkflowModel = session.query(WorkflowModel).filter_by(id=file.workflow_id).first()
|
||||||
|
doc['status'] = workflow.status.value
|
||||||
|
|
||||||
|
documents.append(doc)
|
||||||
|
|
||||||
|
return documents
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def synch_all_studies_with_protocol_builder(user):
|
def synch_all_studies_with_protocol_builder(user):
|
||||||
"""Assures that the studies we have locally for the given user are
|
"""Assures that the studies we have locally for the given user are
|
||||||
|
@ -135,10 +171,10 @@ class StudyService(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __get_workflow_metas(study_id):
|
def __get_workflow_metas(study_id):
|
||||||
# Add in the Workflows for each category
|
# Add in the Workflows for each category
|
||||||
workflow_models = db.session.query(WorkflowModel).\
|
workflow_models = db.session.query(WorkflowModel). \
|
||||||
join(WorkflowSpecModel).\
|
join(WorkflowSpecModel). \
|
||||||
filter(WorkflowSpecModel.is_master_spec == False).\
|
filter(WorkflowSpecModel.is_master_spec == False). \
|
||||||
filter(WorkflowModel.study_id == study_id).\
|
filter(WorkflowModel.study_id == study_id). \
|
||||||
all()
|
all()
|
||||||
workflow_metas = []
|
workflow_metas = []
|
||||||
for workflow in workflow_models:
|
for workflow in workflow_models:
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_00j2iu5" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.0">
|
||||||
|
<bpmn:process id="Process_1gmf4la" isExecutable="true">
|
||||||
|
<bpmn:documentation />
|
||||||
|
<bpmn:startEvent id="StartEvent_1">
|
||||||
|
<bpmn:outgoing>Flow_1k3su2q</bpmn:outgoing>
|
||||||
|
</bpmn:startEvent>
|
||||||
|
<bpmn:endEvent id="EndEvent_1qvyxg7">
|
||||||
|
<bpmn:incoming>Flow_0m7unlb</bpmn:incoming>
|
||||||
|
</bpmn:endEvent>
|
||||||
|
<bpmn:sequenceFlow id="Flow_0m7unlb" sourceRef="Activity_DisplayDocsAndApprovals" targetRef="EndEvent_1qvyxg7" />
|
||||||
|
<bpmn:manualTask id="Activity_DisplayDocsAndApprovals" name="Display Documents and Approvals">
|
||||||
|
<bpmn:documentation>## Approvals
|
||||||
|
| Name | Status | Help |
|
||||||
|
|:-------------- |:-------- |:------ |
|
||||||
|
{% for approval in StudyInfo.approvals -%}
|
||||||
|
| [{{approval.display_name}}](/workflow/{{approval.id}}) | {{approval.status}} | [Context here](/help/{{approval.workflow_spec_id}}) |
|
||||||
|
{% endfor -%}
|
||||||
|
|
||||||
|
|
||||||
|
## Documents
|
||||||
|
| Code | Status | Help |
|
||||||
|
|:-------------- |:-------- |:------ |
|
||||||
|
{% for doc in study.documents_status -%}
|
||||||
|
| [{{doc.code}}](/study/{{doc.study_id}}/workflow/{{doc.workflow_id}}) | {{doc.status}} | [Context here](/help/{{doc.workflow_spec_id}}) |
|
||||||
|
{% endfor -%}
|
||||||
|
</bpmn:documentation>
|
||||||
|
<bpmn:extensionElements>
|
||||||
|
<camunda:properties>
|
||||||
|
<camunda:property name="display_name" value="Documents and Approvals" />
|
||||||
|
</camunda:properties>
|
||||||
|
</bpmn:extensionElements>
|
||||||
|
<bpmn:incoming>Flow_142jtxs</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0m7unlb</bpmn:outgoing>
|
||||||
|
</bpmn:manualTask>
|
||||||
|
<bpmn:scriptTask id="Activity_0a14x7j" name="Load Approvals">
|
||||||
|
<bpmn:incoming>Flow_0c7ryff</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_142jtxs</bpmn:outgoing>
|
||||||
|
<bpmn:script>StudyInfo approvals</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:scriptTask id="Activity_1aju60t" name="Load Documents">
|
||||||
|
<bpmn:incoming>Flow_1k3su2q</bpmn:incoming>
|
||||||
|
<bpmn:outgoing>Flow_0c7ryff</bpmn:outgoing>
|
||||||
|
<bpmn:script>StudyInfo documents_status</bpmn:script>
|
||||||
|
</bpmn:scriptTask>
|
||||||
|
<bpmn:sequenceFlow id="Flow_142jtxs" sourceRef="Activity_0a14x7j" targetRef="Activity_DisplayDocsAndApprovals" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_0c7ryff" sourceRef="Activity_1aju60t" targetRef="Activity_0a14x7j" />
|
||||||
|
<bpmn:sequenceFlow id="Flow_1k3su2q" sourceRef="StartEvent_1" targetRef="Activity_1aju60t" />
|
||||||
|
</bpmn:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1gmf4la">
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0m7unlb_di" bpmnElement="Flow_0m7unlb">
|
||||||
|
<di:waypoint x="710" y="117" />
|
||||||
|
<di:waypoint x="782" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||||
|
<dc:Bounds x="192" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="EndEvent_1qvyxg7_di" bpmnElement="EndEvent_1qvyxg7">
|
||||||
|
<dc:Bounds x="782" y="99" width="36" height="36" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_19nawos_di" bpmnElement="Activity_DisplayDocsAndApprovals">
|
||||||
|
<dc:Bounds x="610" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_1bxk8h3_di" bpmnElement="Activity_0a14x7j">
|
||||||
|
<dc:Bounds x="440" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="Activity_07ytvmv_di" bpmnElement="Activity_1aju60t">
|
||||||
|
<dc:Bounds x="290" y="77" width="100" height="80" />
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_142jtxs_di" bpmnElement="Flow_142jtxs">
|
||||||
|
<di:waypoint x="540" y="117" />
|
||||||
|
<di:waypoint x="610" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_0c7ryff_di" bpmnElement="Flow_0c7ryff">
|
||||||
|
<di:waypoint x="390" y="117" />
|
||||||
|
<di:waypoint x="440" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
<bpmndi:BPMNEdge id="Flow_1k3su2q_di" bpmnElement="Flow_1k3su2q">
|
||||||
|
<di:waypoint x="228" y="117" />
|
||||||
|
<di:waypoint x="290" y="117" />
|
||||||
|
</bpmndi:BPMNEdge>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn:definitions>
|
|
@ -79,6 +79,12 @@ class ExampleDataLoader:
|
||||||
description="TBD",
|
description="TBD",
|
||||||
category_id=0,
|
category_id=0,
|
||||||
display_order=1)
|
display_order=1)
|
||||||
|
self.create_spec(id="documents_approvals",
|
||||||
|
name="documents_approvals",
|
||||||
|
display_name="Documents & Approvals",
|
||||||
|
description="TBD",
|
||||||
|
category_id=0,
|
||||||
|
display_order=2)
|
||||||
|
|
||||||
# Core Info
|
# Core Info
|
||||||
self.create_spec(id="core_info",
|
self.create_spec(id="core_info",
|
||||||
|
|
Loading…
Reference in New Issue