mirror of
https://github.com/sartography/cr-connect-workflow.git
synced 2025-02-22 12:48:25 +00:00
Prefer tasks that share a parent over just the the next available task when returning the next_task in the workflow processor.
This commit is contained in:
parent
ef7ee284b2
commit
59f605c3df
@ -57,7 +57,7 @@ def get_document_directory(study_id, workflow_id=None):
|
||||
if file.irb_doc_code in doc_dict:
|
||||
doc_code = doc_dict[file.irb_doc_code]
|
||||
else:
|
||||
doc_code = {'category1': "Unknown", 'category2': None, 'category3': None}
|
||||
doc_code = {'category1': "Unknown", 'category2': '', 'category3': ''}
|
||||
if workflow_id:
|
||||
expand = file.workflow_id == int(workflow_id)
|
||||
else:
|
||||
|
@ -244,6 +244,7 @@ def __update_task(processor, task, data, user):
|
||||
here because we need to do it multiple times when completing all tasks in
|
||||
a multi-instance task"""
|
||||
task.update_data(data)
|
||||
WorkflowService.post_process_form(task) # some properties may update the data store.
|
||||
processor.complete_task(task)
|
||||
processor.do_engine_steps()
|
||||
processor.save()
|
||||
|
@ -26,7 +26,8 @@ class Task(object):
|
||||
PROP_EXTENSIONS_TITLE = "display_name"
|
||||
|
||||
|
||||
# Autocomplete field
|
||||
# Field Types
|
||||
FIELD_TYPE_FILE = "file"
|
||||
FIELD_TYPE_AUTO_COMPLETE = "autocomplete"
|
||||
FIELD_PROP_AUTO_COMPLETE_MAX = "autocomplete_num" # Not used directly, passed in from the front end.
|
||||
|
||||
@ -59,6 +60,10 @@ class Task(object):
|
||||
FIELD_PROP_REPLEAT_TITLE = "repeat_title"
|
||||
FIELD_PROP_REPLEAT_BUTTON = "repeat_button_label"
|
||||
|
||||
# File specific field properties
|
||||
FIELD_PROP_DOC_CODE = "doc_code" # to associate a file upload field with a doc code
|
||||
FIELD_PROP_FILE_DATA = "file_data" # to associate a bit of data with a specific file upload file.
|
||||
|
||||
# Additional properties
|
||||
FIELD_PROP_ENUM_TYPE = "enum_type"
|
||||
FIELD_PROP_TEXT_AREA_ROWS = "rows"
|
||||
|
@ -90,7 +90,7 @@ class FileModel(db.Model):
|
||||
# it instead, hide it in the interface.
|
||||
is_review = db.Column(db.Boolean, default=False, nullable=True)
|
||||
archived = db.Column(db.Boolean, default=False, nullable=False)
|
||||
tags = relationship("DataStoreModel", cascade="all,delete", backref="file")
|
||||
data_stores = relationship("DataStoreModel", cascade="all,delete", backref="file")
|
||||
|
||||
class File(object):
|
||||
@classmethod
|
||||
@ -123,6 +123,11 @@ class File(object):
|
||||
else:
|
||||
instance.last_modified = None
|
||||
instance.latest_version = None
|
||||
|
||||
instance.data_store = {}
|
||||
for ds in model.data_stores:
|
||||
instance.data_store[ds.key] = ds.value
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
@ -142,7 +147,7 @@ class FileSchema(Schema):
|
||||
fields = ["id", "name", "is_status", "is_reference", "content_type",
|
||||
"primary", "primary_process_id", "workflow_spec_id", "workflow_id",
|
||||
"irb_doc_code", "last_modified", "latest_version", "type", "categories",
|
||||
"description", "category", "description", "download_name", "size"]
|
||||
"description", "category", "download_name", "size", "data_store"]
|
||||
|
||||
unknown = INCLUDE
|
||||
type = EnumField(FileType)
|
||||
|
@ -100,16 +100,6 @@ class FileService(object):
|
||||
|
||||
@staticmethod
|
||||
def add_workflow_file(workflow_id, irb_doc_code, name, content_type, binary_data):
|
||||
"""Create a new file and associate it with the workflow
|
||||
Please note that the irb_doc_code MUST be a known file in the irb_documents.xslx reference document."""
|
||||
if not FileService.is_allowed_document(irb_doc_code):
|
||||
raise ApiError("invalid_form_field_key",
|
||||
"When uploading files, the form field id must match a known document in the "
|
||||
"irb_docunents.xslx reference file. This code is not found in that file '%s'" % irb_doc_code)
|
||||
|
||||
"""Assure this is unique to the workflow, task, and document code AND the Name
|
||||
Because we will allow users to upload multiple files for the same form field
|
||||
in some cases """
|
||||
file_model = session.query(FileModel)\
|
||||
.filter(FileModel.workflow_id == workflow_id)\
|
||||
.filter(FileModel.name == name)\
|
||||
|
@ -22,6 +22,7 @@ from jinja2 import Template
|
||||
from crc import db, app
|
||||
from crc.api.common import ApiError
|
||||
from crc.models.api_models import Task, MultiInstanceType, WorkflowApi
|
||||
from crc.models.data_store import DataStoreModel
|
||||
from crc.models.file import LookupDataModel, FileModel
|
||||
from crc.models.study import StudyModel
|
||||
from crc.models.task_event import TaskEventModel
|
||||
@ -242,6 +243,25 @@ class WorkflowService(object):
|
||||
f'The field {field.id} contains an unsupported '
|
||||
f'property: {name}', task=task)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def post_process_form(task):
|
||||
"""Looks through the fields in a submitted form, acting on any properties."""
|
||||
for field in task.task_spec.form.fields:
|
||||
if field.has_property(Task.FIELD_PROP_DOC_CODE) and \
|
||||
field.type == Task.FIELD_TYPE_FILE:
|
||||
file_id = task.data[field.id]
|
||||
file = db.session.query(FileModel).filter(FileModel.id == file_id).first()
|
||||
doc_code = WorkflowService.evaluate_property(Task.FIELD_PROP_DOC_CODE, field, task)
|
||||
file.irb_doc_code = doc_code
|
||||
db.session.commit()
|
||||
# Set the doc code on the file.
|
||||
if field.has_property(Task.FIELD_PROP_FILE_DATA) and \
|
||||
field.get_property(Task.FIELD_PROP_FILE_DATA) in task.data:
|
||||
file_id = task.data[field.get_property(Task.FIELD_PROP_FILE_DATA)]
|
||||
data_store = DataStoreModel(file_id=file_id, key=field.id, value=task.data[field.id])
|
||||
db.session.add(data_store)
|
||||
|
||||
@staticmethod
|
||||
def evaluate_property(property_name, field, task):
|
||||
expression = field.get_property(property_name)
|
||||
|
@ -1,13 +1,14 @@
|
||||
<?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" id="Definitions_1wrlvk8" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.4.1">
|
||||
<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" id="Definitions_1wrlvk8" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.7.3">
|
||||
<bpmn:process id="Finance" isExecutable="true">
|
||||
<bpmn:startEvent id="StartEvent_1p6s47e">
|
||||
<bpmn:outgoing>SequenceFlow_0ea9hvd</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:endEvent id="EndEvent_14p904o">
|
||||
<bpmn:incoming>SequenceFlow_1h0d349</bpmn:incoming>
|
||||
<bpmn:incoming>Flow_0t55959</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:userTask id="Task_112migv" name="Upload Executed Non-Funded" camunda:formKey="FormKey_ExecutedNonFunded">
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0ea9hvd" sourceRef="StartEvent_1p6s47e" targetRef="Activity_0neioh9" />
|
||||
<bpmn:userTask id="Activity_0neioh9" name="Upload Executed Non-Funded" camunda:formKey="FormKey_ExecutedNonFunded">
|
||||
<bpmn:documentation>#### Non-Funded Executed Agreement
|
||||
|
||||
|
||||
@ -15,40 +16,55 @@
|
||||
OGC will upload the Non-Funded Executed Agreement after it has been negotiated by OSP contract negotiator.</bpmn:documentation>
|
||||
<bpmn:extensionElements>
|
||||
<camunda:formData>
|
||||
<camunda:formField id="UVACompl_PRCAppr" label="Non-Funded Executed Agreement" type="file">
|
||||
<camunda:formField id="file_type" type="enum" defaultValue="FileType1">
|
||||
<camunda:value id="FileType1" name="My First file type" />
|
||||
<camunda:value id="FileType2" name="My second file type" />
|
||||
</camunda:formField>
|
||||
<camunda:formField id="Some_File" label="Upload File" type="file">
|
||||
<camunda:properties>
|
||||
<camunda:property id="group" value="upload" />
|
||||
<camunda:property id="repeat" value="upload" />
|
||||
<camunda:property id="group" value="PCRApproval" />
|
||||
<camunda:property id="doc_code" value="file_type" />
|
||||
</camunda:properties>
|
||||
</camunda:formField>
|
||||
<camunda:formField id="Language" label="Language" type="string" defaultValue="Engish">
|
||||
<camunda:properties>
|
||||
<camunda:property id="group" value="PCRApproval" />
|
||||
<camunda:property id="file_data" value="Some_File" />
|
||||
</camunda:properties>
|
||||
</camunda:formField>
|
||||
<camunda:formField id="Date" label="Version Date" type="date">
|
||||
<camunda:properties>
|
||||
<camunda:property id="group" value="PCRApproval" />
|
||||
<camunda:property id="file_data" value="Some_File" />
|
||||
</camunda:properties>
|
||||
</camunda:formField>
|
||||
</camunda:formData>
|
||||
</bpmn:extensionElements>
|
||||
<bpmn:incoming>SequenceFlow_0ea9hvd</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_1h0d349</bpmn:outgoing>
|
||||
<bpmn:outgoing>Flow_0t55959</bpmn:outgoing>
|
||||
<bpmn:standardLoopCharacteristics />
|
||||
</bpmn:userTask>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_0ea9hvd" sourceRef="StartEvent_1p6s47e" targetRef="Task_112migv" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1h0d349" sourceRef="Task_112migv" targetRef="EndEvent_14p904o" />
|
||||
<bpmn:sequenceFlow id="Flow_0t55959" sourceRef="Activity_0neioh9" targetRef="EndEvent_14p904o" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Finance">
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0ea9hvd_di" bpmnElement="SequenceFlow_0ea9hvd">
|
||||
<di:waypoint x="148" y="117" />
|
||||
<di:waypoint x="210" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0t55959_di" bpmnElement="Flow_0t55959">
|
||||
<di:waypoint x="310" y="117" />
|
||||
<di:waypoint x="392" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNShape id="StartEvent_1p6s47e_di" bpmnElement="StartEvent_1p6s47e">
|
||||
<dc:Bounds x="112" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_14p904o_di" bpmnElement="EndEvent_14p904o">
|
||||
<dc:Bounds x="682" y="99" width="36" height="36" />
|
||||
<dc:Bounds x="392" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1peopdt_di" bpmnElement="Task_112migv">
|
||||
<dc:Bounds x="350" y="77" width="100" height="80" />
|
||||
<bpmndi:BPMNShape id="Activity_0neioh9_di" bpmnElement="Activity_0neioh9">
|
||||
<dc:Bounds x="210" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_0ea9hvd_di" bpmnElement="SequenceFlow_0ea9hvd">
|
||||
<di:waypoint x="148" y="117" />
|
||||
<di:waypoint x="350" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1h0d349_di" bpmnElement="SequenceFlow_1h0d349">
|
||||
<di:waypoint x="450" y="117" />
|
||||
<di:waypoint x="682" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
|
@ -8,6 +8,7 @@ from crc.models.file import FileModel, FileType, FileSchema, FileModelSchema
|
||||
from crc.models.workflow import WorkflowSpecModel
|
||||
from crc.services.file_service import FileService
|
||||
from crc.services.workflow_processor import WorkflowProcessor
|
||||
from crc.models.data_store import DataStoreModel
|
||||
from example_data import ExampleDataLoader
|
||||
|
||||
|
||||
@ -232,6 +233,17 @@ class TestFilesApi(BaseTest):
|
||||
self.assertEqual("text/xml; charset=utf-8", rv.content_type)
|
||||
self.assertTrue(rv.content_length > 1)
|
||||
|
||||
def test_get_file_contains_data_store_elements(self):
|
||||
self.load_example_data()
|
||||
spec = session.query(WorkflowSpecModel).first()
|
||||
file = session.query(FileModel).filter_by(workflow_spec_id=spec.id).first()
|
||||
ds = DataStoreModel(key="my_key", value="my_value", file_id=file.id);
|
||||
db.session.add(ds)
|
||||
rv = self.app.get('/v1.0/file/%i' % file.id, headers=self.logged_in_headers())
|
||||
self.assert_success(rv)
|
||||
json_data = json.loads(rv.get_data(as_text=True))
|
||||
self.assertEqual("my_value", json_data['data_store']['my_key'])
|
||||
|
||||
def test_get_files_for_form_field_returns_only_those_files(self):
|
||||
self.create_reference_document()
|
||||
workflow = self.create_workflow('file_upload_form')
|
||||
|
Loading…
x
Reference in New Issue
Block a user