def checklist_workflow(): EXTERNAL_REVIEW_GROUP = 'External Reviewer' EXECUTIVE_GROUP = 'EC-Executive' setup_workflow_graph(Checklist, auto_start=True, nodes={ 'start': Args(Generic, start=True, name=_("Start")), 'external_review': Args(ExternalReview, name=_("External Review"), group=EXTERNAL_REVIEW_GROUP, is_delegatable=False, is_dynamic=True), 'external_review_review': Args(ExternalReviewReview, name=_("External Review Review"), group=EXECUTIVE_GROUP), }, edges={ ('start', 'external_review'): Args(guard=is_external_review_checklist), ('external_review', 'external_review_review'): None, ('external_review_review', 'external_review'): Args(guard=checklist_review_review_failed), })
def workflow_graph_needs_upgrade(graph, nodes, edges): existing_nodes = {} for name, args in nodes.iteritems(): args.pop('group', None) try: existing_nodes[name] = args.apply(graph.get_node) except (Node.DoesNotExist, Node.MultipleObjectsReturned): return True for node_names, args in edges.iteritems(): if not args: args = Args() from_name, to_name = node_names args.update(existing_nodes[to_name]) try: args.apply(existing_nodes[from_name].get_edge) except Edge.DoesNotExist: return True return False
def setup_workflow_graph(model, nodes=None, edges=None, force=False, **kwargs): """ created a new workflow graph if a graph with the same structure does not already exists. old graphs will loose their auto_start=True flag. """ try: graph, created = Graph.objects.get_or_create(model=model, **kwargs) except Graph.MultipleObjectsReturned: raise ValueError("There is more than one graph for %s with %s" % (model, kwargs)) if not created: if not force and not workflow_graph_needs_upgrade(graph, nodes, edges): return False graph.auto_start = False graph.save() graph = Graph.objects.create(model=model, **kwargs) node_instances = {} for name, args in nodes.iteritems(): args.setdefault('name', " ".join(camel_split(args[0].__name__))) group = args.pop('group', None) node = args.apply(graph.create_node) node_instances[name] = node if group: task_type = TaskType.objects.get(workflow_node=node) try: task_type.groups.add(Group.objects.get(name=group)) except Group.DoesNotExist: print "no such group: %s" % group raise for node_names, args in edges.iteritems(): if not args: args = Args() from_name, to_name = node_names args.update(node_instances[to_name]) args.apply(node_instances[from_name].add_edge) return True
def setup_workflow_graph(model, nodes=None, edges=None, force=True, **kwargs): """ created a new workflow graph if a graph with the same structure does not already exists. old graphs will loose their auto_start=True flag. """ if isinstance(edges, dict): edges = edges.items() try: graph, created = Graph.objects.get_or_create(model=model, **kwargs) except Graph.MultipleObjectsReturned: raise ValueError("There is more than one graph for %s with %s" % (model, kwargs)) if not created: # FIXME: workflow_graph_needs_upgrade is broken because it alters the Args instance. if not force and not workflow_graph_needs_upgrade(graph, nodes, edges): return False graph.auto_start = False graph.save() graph = Graph.objects.create(model=model, **kwargs) node_instances = {} for name, args in nodes.items(): args.setdefault('name', " ".join(camel_split(args[0].__name__))) args.setdefault('uid', name) group = args.pop('group', None) is_delegatable = args.pop('is_delegatable', None) is_dynamic = args.pop('is_dynamic', None) node = args.apply(graph.create_node) node_instances[name] = node if group: task_type = TaskType.objects.get(workflow_node=node) task_type.group = Group.objects.get(name=group) task_type.save() if not is_delegatable is None: task_type = TaskType.objects.get(workflow_node=node) task_type.is_delegatable = is_delegatable task_type.save() if not is_dynamic is None: task_type = TaskType.objects.get(workflow_node=node) task_type.is_dynamic = is_dynamic task_type.save() for node_names, args in edges: if not args: args = Args() from_name, to_name = node_names args.update(node_instances[to_name]) args.apply(node_instances[from_name].add_edge) return True
def workflow_graph_needs_upgrade(graph, nodes, edges): existing_nodes = {} nodes = deepcopy(nodes) for name, args in nodes.items(): args.setdefault('uid', name) args.pop('group', None) try: existing_nodes[name] = args.apply(graph.get_node) except (Node.DoesNotExist, Node.MultipleObjectsReturned): return True edges = deepcopy(edges) for node_names, args in edges: if not args: args = Args() from_name, to_name = node_names args.update(existing_nodes[to_name]) try: args.apply(existing_nodes[from_name].get_edge) except Edge.DoesNotExist: return True return False
def document_types(): names = ( Args(_("Covering Letter"), "coveringletter"), Args(_("patient information"), "patientinformation"), Args(_("insurancecertificate"), "insurancecertificate"), Args(_("study protocol"), "protocol"), Args(_("Investigator's Brochure"), "investigatorsbrochure", is_downloadable=False), Args(_("Amendment"), "amendment"), Args(_("Curriculum Vitae (CV)"), "cv"), Args(_("Conflict of Interest"), "conflictofinterest"), Args(_("Case Report Form (CRF)"), "crf"), Args(_("EudraCT Form"), "eudract"), Args(_("adverse reaction report"), "adversereaction"), Args(_("Statement on a review"), "reviewstatement"), Args(_("Questionnaire"), "questionnaire"), Args(_("Signed Page"), "signed_page"), Args(_("Manual"), "manual"), Args(_("Declaration of conformity"), "conformity_declaration"), Args(_("other"), "other"), # internal document types; not user visible Args(_("Submission Form"), "submissionform", is_hidden=True), Args(_("Checklist"), "checklist", is_hidden=True), Args(_("vote"), "votes", is_hidden=True), Args(_("Notification"), "notification", is_hidden=True), Args(_("Notification Answer"), "notification_answer", is_hidden=True), Args(_("Invoice"), "invoice", is_hidden=True), Args(_("Checklist Payment"), "checklist_payment", is_hidden=True), Args(_("Meeting Protocol"), "meeting_protocol", is_hidden=True), Args(_("Meeting ZIP"), "meeting_zip", is_hidden=True), ) for args in names: name, identifier = args DocumentType.objects.update_or_create(identifier=identifier, defaults={ 'name': name, 'is_hidden': args.get('is_hidden', False), 'is_downloadable': args.get( 'is_downloadable', True), })
def notification_workflow(): EXECUTIVE_GROUP = 'EC-Executive' OFFICE_GROUP = 'EC-Office' SIGNING_GROUP = 'EC-Signing' setup_workflow_graph( Notification, auto_start=True, nodes={ 'start': Args(Generic, start=True, name='Start'), 'safety_review': Args(SimpleNotificationReview, group=OFFICE_GROUP, name=_('Safety Review')), 'distribute_notification_answer': Args(AutoDistributeNotificationAnswer, name=_('Distribute Notification Answer')), # reports 'office_report_review': Args(SimpleNotificationReview, group=OFFICE_GROUP, name=_('Office Notification Review')), 'executive_report_review': Args(EditNotificationAnswer, group=EXECUTIVE_GROUP, name=_('Executive Notification Review')), # amendments 'initial_amendment_review': Args(InitialAmendmentReview, group=OFFICE_GROUP, name=_('Initial Amendment Review')), 'executive_amendment_review': Args(EditNotificationAnswer, group=EXECUTIVE_GROUP, name=_('Amendment Review')), 'wait_for_meeting': Args(WaitForMeeting, name='Wait For Meeting'), 'amendment_split': Args(Generic, name='Amendment Split'), 'notification_answer_signing': Args(SignNotificationAnswer, group=SIGNING_GROUP, name=_('Amendment Answer Signing')), }, edges=( (('start', 'safety_review'), Args(guard=is_susar)), (('start', 'office_report_review'), Args(guard=is_report)), (('start', 'office_report_review'), Args(guard=is_center_close)), (('start', 'initial_amendment_review'), Args(guard=is_amendment)), # safety reports (('safety_review', 'executive_report_review'), Args(guard=is_rejected_and_final, negated=True)), (('safety_review', 'distribute_notification_answer'), Args(guard=is_rejected_and_final)), # reports (('office_report_review', 'executive_report_review'), Args(guard=is_rejected_and_final, negated=True)), (('office_report_review', 'distribute_notification_answer'), Args(guard=is_rejected_and_final)), (('executive_report_review', 'start'), Args(guard=needs_further_review)), (('executive_report_review', 'distribute_notification_answer'), Args(guard=needs_further_review, negated=True)), # amendments (('initial_amendment_review', 'executive_amendment_review'), Args(guard=is_rejected_and_final, negated=True)), (('initial_amendment_review', 'distribute_notification_answer'), Args(guard=is_rejected_and_final)), (('executive_amendment_review', 'initial_amendment_review'), Args(guard=needs_further_review)), (('executive_amendment_review', 'amendment_split'), Args(guard=needs_further_review, negated=True)), (('amendment_split', 'wait_for_meeting'), Args(guard=is_substantial)), (('amendment_split', 'notification_answer_signing'), Args(guard=needs_signature)), (('amendment_split', 'distribute_notification_answer'), Args(guard=needs_distribution)), (('wait_for_meeting', 'initial_amendment_review'), Args(guard=needs_further_review)), (('wait_for_meeting', 'notification_answer_signing'), Args(guard=needs_further_review, negated=True)), ))
def submission_workflow(): thesis_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='thesis_review') expedited_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='expedited_review') localec_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='localec_review') statistical_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='statistic_review') insurance_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='insurance_review') legal_and_patient_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='legal_review') specialist_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='specialist_review') gcp_review_checklist_blueprint = ChecklistBlueprint.objects.get( slug='gcp_review') EXECUTIVE_GROUP = 'EC-Executive' OFFICE_GROUP = 'EC-Office' BOARD_MEMBER_GROUP = 'Board Member' INSURANCE_REVIEW_GROUP = 'Insurance Reviewer' STATISTIC_REVIEW_GROUP = 'Statistic Reviewer' GCP_REVIEW_GROUP = 'GCP Reviewer' SPECIALIST_GROUP = 'Specialist' setup_workflow_graph( Submission, auto_start=True, nodes={ 'start': Args(Generic, start=True, name="Start"), 'resubmission': Args(Resubmission, name=_("Resubmission")), 'b2_resubmission': Args(Resubmission, name=_("B2 Resubmission")), 'b2_review': Args(InitialB2ResubmissionReview, name=_("Office B2 Resubmission Review"), group=OFFICE_GROUP), 'executive_b2_review': Args(B2ResubmissionReview, name=_("Executive B2 Resubmission Review"), group=EXECUTIVE_GROUP), 'initial_review': Args(InitialReview, group=OFFICE_GROUP, name=_("Initial Review")), 'initial_review_barrier': Args(Generic, name="Initial Review Barrier"), 'categorization': Args(Categorization, group=EXECUTIVE_GROUP, name=_("Categorization")), 'categorization_review': Args(CategorizationReview, group=OFFICE_GROUP, name=_("Categorization Review")), 'paper_submission_review': Args(PaperSubmissionReview, group=OFFICE_GROUP, name=_("Paper Submission Review")), 'legal_and_patient_review': Args(ChecklistReview, data=legal_and_patient_review_checklist_blueprint, name=_("Legal and Patient Review"), group=OFFICE_GROUP, is_dynamic=True), 'insurance_review': Args(ChecklistReview, data=insurance_review_checklist_blueprint, name=_("Insurance Review"), group=INSURANCE_REVIEW_GROUP, is_dynamic=True), 'statistical_review': Args(ChecklistReview, data=statistical_review_checklist_blueprint, name=_("Statistical Review"), group=STATISTIC_REVIEW_GROUP, is_dynamic=True), 'specialist_review': Args(ChecklistReview, data=specialist_review_checklist_blueprint, name=_("Specialist Review"), group=SPECIALIST_GROUP, is_delegatable=False, is_dynamic=True), 'gcp_review': Args(ChecklistReview, data=gcp_review_checklist_blueprint, name=_("GCP Review"), group=GCP_REVIEW_GROUP, is_dynamic=True), # retrospective thesis lane 'initial_thesis_review': Args(InitialReview, name=_("Initial Thesis Review"), group=OFFICE_GROUP), 'thesis_recommendation': Args(ChecklistReview, data=thesis_review_checklist_blueprint, name=_("Thesis Recommendation"), group=OFFICE_GROUP), # expedited_lane 'expedited_recommendation_split': Args(ExpeditedRecommendationSplit, name=_("Expedited Recommendation Split")), 'expedited_recommendation': Args(ChecklistReview, data=expedited_review_checklist_blueprint, name=_("Expedited Recommendation"), group=BOARD_MEMBER_GROUP), # local ec lane 'localec_recommendation': Args(ChecklistReview, data=localec_review_checklist_blueprint, name=_("Local EC Recommendation"), group=EXECUTIVE_GROUP), # retrospective thesis, expedited and local ec lanes 'vote_preparation': Args(VotePreparation, name=_("Vote Preparation"), group=OFFICE_GROUP), }, edges={ ('start', 'initial_review'): Args(guard=is_retrospective_thesis, negated=True), ('start', 'initial_thesis_review'): Args(guard=is_retrospective_thesis), ('initial_review', 'initial_review_barrier'): None, ('initial_thesis_review', 'initial_review_barrier'): None, ('initial_review_barrier', 'resubmission'): Args(guard=is_acknowledged, negated=True), ('initial_review_barrier', 'categorization'): Args(guard=is_acknowledged_and_initial_submission), ('categorization', 'categorization_review'): Args(guard=needs_categorization_review), ('initial_review_barrier', 'paper_submission_review'): Args(guard=is_acknowledged_and_initial_submission), ('b2_resubmission', 'b2_review'): None, ('b2_review', 'executive_b2_review'): Args(guard=needs_executive_b2_review), ('b2_review', 'b2_resubmission'): Args(guard=is_still_b2), ('executive_b2_review', 'b2_review'): None, # retrospective thesis lane ('categorization', 'thesis_recommendation'): Args(guard=is_retrospective_thesis), ('thesis_recommendation', 'categorization'): Args(guard=has_thesis_recommendation, negated=True), ('thesis_recommendation', 'vote_preparation'): Args(guard=needs_thesis_vote_preparation), # expedited lane ('categorization', 'expedited_recommendation_split'): None, ('expedited_recommendation_split', 'expedited_recommendation'): Args(guard=is_expedited), ('expedited_recommendation', 'vote_preparation'): Args(guard=needs_expedited_vote_preparation), ('expedited_recommendation', 'categorization'): Args(guard=needs_expedited_recategorization), # local ec lane ('categorization', 'localec_recommendation'): Args(guard=needs_localec_recommendation), ('localec_recommendation', 'vote_preparation'): Args(guard=needs_localec_vote_preparation), ('localec_recommendation', 'categorization'): Args(guard=has_localec_recommendation, negated=True), }) # translations for legacy task types _('Executive Vote Finalization') _('Insurance Amendment Review') _('Insurance B2 Resubmission Review') _('Office Vote Review (legacy)') _('Thesis Recommendation Review')
def vote_workflow(): EXECUTIVE_GROUP = 'EC-Executive' OFFICE_GROUP = 'EC-Office' SIGNING_GROUP = 'EC-Signing' setup_workflow_graph( Vote, auto_start=True, nodes={ 'executive_vote_review': Args(VoteReview, name=_("Executive Vote Review"), group=EXECUTIVE_GROUP), 'internal_vote_review': Args(VoteReview, name=_("Internal Vote Review"), group=OFFICE_GROUP), 'office_vote_finalization': Args(VoteReview, start=True, name=_("Office Vote Finalization"), group=OFFICE_GROUP), 'final_office_vote_review': Args(VoteReview, name=_("Office Vote Review"), group=OFFICE_GROUP), 'vote_signing': Args(VoteSigning, group=SIGNING_GROUP, name=_("Vote Signing")), }, edges={ ('office_vote_finalization', 'internal_vote_review'): Args(guard=internal_vote_review_required), ('office_vote_finalization', 'executive_vote_review'): Args(guard=internal_vote_review_required, negated=True), ('internal_vote_review', 'office_vote_finalization'): Args(guard=is_final, negated=True), ('internal_vote_review', 'executive_vote_review'): Args(guard=is_final), ('executive_vote_review', 'final_office_vote_review'): Args(guard=is_final, negated=True), ('executive_vote_review', 'vote_signing'): Args(guard=is_final), ('final_office_vote_review', 'executive_vote_review'): None, })
from ecs.utils import Args checklist_questions = { 'thesis_review': [ Args( '1', 'Handelt es sich um eine retrospektive Diplomstudie und geben Sie eine positive Empfehlung ab?' ), # XXX: dont change this number ], 'statistic_review': [ Args('1', 'Ist das Studienziel ausreichend definiert?'), Args( '2', 'Ist das Design der Studie geeignet, das Studienziel zu erreichen?' ), Args('3', 'Ist die Studienpopulation ausreichend definiert?'), Args('4', 'Sind die Zielvariablen geeignet definiert?'), Args('5', 'Ist die statistische Analyse beschrieben, und ist sie adäquat?'), Args('6', 'Ist die Größe der Stichprobe ausreichend begründet?'), ], 'legal_review': [ Args( '1', 'Entspricht die Patienteninformation in allen Punkten den Anforderungen?' ), ], 'insurance_review': [ Args( '1', "Sind die vorgelegten Unterlagen zur Versicherung vollständig und akzeptabel?"