Merge pull request #101 from sartography/feature/allow-dot-notation-in-forms

Feature/allow dot notation in forms
This commit is contained in:
Kevin Burnett 2022-09-29 15:09:26 +00:00 committed by GitHub
commit 6d6e0e7efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 195 additions and 16 deletions

View File

@ -11,7 +11,6 @@ from flask_bpmn.models.db import SpiffworkflowBaseDBModel
from marshmallow import INCLUDE from marshmallow import INCLUDE
from marshmallow import Schema from marshmallow import Schema
from marshmallow_enum import EnumField # type: ignore from marshmallow_enum import EnumField # type: ignore
from SpiffWorkflow.navigation import NavItem # type: ignore
from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore
from sqlalchemy import ForeignKey from sqlalchemy import ForeignKey
from sqlalchemy.orm import deferred from sqlalchemy.orm import deferred
@ -54,20 +53,6 @@ class NavigationItemSchema(Schema):
marshmallow.fields.Nested(lambda: NavigationItemSchema()) marshmallow.fields.Nested(lambda: NavigationItemSchema())
) )
@marshmallow.post_load
def make_nav(self, data: dict[str, Any], **kwargs: dict) -> NavItem:
"""Make_nav."""
state = data.pop("state", None)
task_id = data.pop("task_id", None)
children = data.pop("children", [])
spec_type = data.pop("spec_type", None)
item = NavItem(**data)
item.state = state
item.task_id = task_id
item.children = children
item.spec_type = spec_type
return item
class ProcessInstanceStatus(SpiffEnum): class ProcessInstanceStatus(SpiffEnum):
"""ProcessInstanceStatus.""" """ProcessInstanceStatus."""

View File

@ -275,7 +275,8 @@ class ProcessInstanceService:
Abstracted here because we need to do it multiple times when completing all tasks in Abstracted here because we need to do it multiple times when completing all tasks in
a multi-instance task. a multi-instance task.
""" """
spiff_task.update_data(data) dot_dct = ProcessInstanceService.create_dot_dict(data)
spiff_task.update_data(dot_dct)
# ProcessInstanceService.post_process_form(spiff_task) # some properties may update the data store. # ProcessInstanceService.post_process_form(spiff_task) # some properties may update the data store.
processor.complete_task(spiff_task) processor.complete_task(spiff_task)
# Log the action before doing the engine steps, as doing so could effect the state of the task # Log the action before doing the engine steps, as doing so could effect the state of the task
@ -342,6 +343,14 @@ class ProcessInstanceService:
ProcessInstanceService.set_dot_value(field.id, value, data) ProcessInstanceService.set_dot_value(field.id, value, data)
return data return data
@staticmethod
def create_dot_dict(data: dict) -> dict[str, Any]:
"""Create_dot_dict."""
dot_dict: dict[str, Any] = {}
for key, value in data.items():
ProcessInstanceService.set_dot_value(key, value, dot_dict)
return dot_dict
@staticmethod @staticmethod
def get_dot_value(path: str, source: dict) -> Any: def get_dot_value(path: str, source: dict) -> Any:
"""Get_dot_value.""" """Get_dot_value."""

View File

@ -0,0 +1,74 @@
<?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:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:spiffworkflow="http://spiffworkflow.org/bpmn/schema/1.0/core" id="Definitions_96f6665" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="3.0.0-dev">
<bpmn:correlationProperty id="message_correlation_property" name="Message Correlation Property">
<bpmn:correlationPropertyRetrievalExpression messageRef="message_send">
<bpmn:formalExpression>to</bpmn:formalExpression>
</bpmn:correlationPropertyRetrievalExpression>
<bpmn:correlationPropertyRetrievalExpression messageRef="message_response">
<bpmn:formalExpression>from.name</bpmn:formalExpression>
</bpmn:correlationPropertyRetrievalExpression>
</bpmn:correlationProperty>
<bpmn:message id="message_send" name="Message Send">
<bpmn:extensionElements>
<spiffworkflow:messagePayload>{"to": "the_recipient1" }</spiffworkflow:messagePayload>
</bpmn:extensionElements>
</bpmn:message>
<bpmn:message id="message_response" name="Message Response">
<bpmn:extensionElements>
<spiffworkflow:messagePayload>{"from": {"name": "the_sender"}}</spiffworkflow:messagePayload>
</bpmn:extensionElements>
</bpmn:message>
<bpmn:correlationProperty id="correlation_property_one" name="Correlation Property One">
<bpmn:correlationPropertyRetrievalExpression messageRef="message_send">
<bpmn:formalExpression>new</bpmn:formalExpression>
</bpmn:correlationPropertyRetrievalExpression>
</bpmn:correlationProperty>
<bpmn:process id="test_dot_notation" name="Test Dot Notation" isExecutable="true">
<bpmn:startEvent id="start" name="Start">
<bpmn:outgoing>Flow_0dbnzbi</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0dbnzbi" sourceRef="start" targetRef="get_data" />
<bpmn:endEvent id="end" name="End">
<bpmn:incoming>Flow_0nt355i</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="Flow_0nt355i" sourceRef="get_data" targetRef="end" />
<bpmn:userTask id="get_data" name="Get Data">
<bpmn:extensionElements>
<spiffworkflow:properties>
<spiffworkflow:property name="formJsonSchemaFilename" value="json_schema.json" />
<spiffworkflow:property name="formUiSchemaFilename" value="ui_schema.json" />
</spiffworkflow:properties>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0dbnzbi</bpmn:incoming>
<bpmn:outgoing>Flow_0nt355i</bpmn:outgoing>
</bpmn:userTask>
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="test_dotnotation">
<bpmndi:BPMNEdge id="Flow_0dbnzbi_di" bpmnElement="Flow_0dbnzbi">
<di:waypoint x="208" y="230" />
<di:waypoint x="260" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0nt355i_di" bpmnElement="Flow_0nt355i">
<di:waypoint x="360" y="230" />
<di:waypoint x="412" y="230" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Event_1uf4njx_di" bpmnElement="start">
<dc:Bounds x="172" y="212" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="178" y="255" width="24" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_00d0dwr_di" bpmnElement="end">
<dc:Bounds x="412" y="212" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="420" y="255" width="20" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_1vgvg3h_di" bpmnElement="get_data">
<dc:Bounds x="260" y="190" width="100" height="80" />
<bpmndi:BPMNLabel />
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn:definitions>

View File

@ -0,0 +1,36 @@
{
"title": "Submit Invoice",
"description": "Information for submitting an invoice.",
"type": "object",
"required": [
"invoice.contributorName",
"invoice.contributorId",
"invoice.invoiceId",
"invoice.invoiceAmount",
"invoice.dueDate"
],
"properties": {
"invoice.contributorName": {
"type": "string",
"title": "Contributor Name"
},
"invoice.contributorId": {
"type": "integer",
"title": "Contributor Id",
"minLength": 2
},
"invoice.invoiceId": {
"type": "integer",
"title": "Invoice Id",
"minLength": 4
},
"invoice.invoiceAmount": {
"type": "number",
"title": "Invoice Amount"
},
"invoice.dueDate": {
"type": "string",
"title": "Due Date"
}
}
}

View File

@ -0,0 +1,19 @@
{
"invoice.contributorName": {
"ui:autofocus": true,
"ui:emptyValue": ""
},
"invoice.contributorId": {
"ui:emptyValue": "Enter your Status Contributor ID"
},
"invoice.invoiceId": {
"ui:title": "Status Invoice ID",
"ui:description": "Enter the Status Invoice ID found in the upper left"
},
"invoice.invoiceAmount": {
"ui:help": "Amount in Euros"
},
"invoice.dueDate": {
"ui:widget": "date"
}
}

View File

@ -0,0 +1,56 @@
"""Test_various_bpmn_constructs."""
from flask.app import Flask
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from spiffworkflow_backend.services.process_instance_processor import (
ProcessInstanceProcessor,
)
from spiffworkflow_backend.services.process_instance_service import (
ProcessInstanceService,
)
class TestDotNotation(BaseTest):
"""TestVariousBpmnConstructs."""
def test_dot_notation(
self, app: Flask, with_db_and_bpmn_file_cleanup: None
) -> None:
"""Test_form_data_conversion_to_dot_dict."""
process_model = load_test_spec(
"test_dot_notation",
bpmn_file_name="diagram.bpmn",
process_model_source_directory="dot_notation",
)
current_user = self.find_or_create_user()
process_instance = self.create_process_instance_from_process_model(
process_model
)
processor = ProcessInstanceProcessor(process_instance)
processor.do_engine_steps(save=True)
user_task = processor.get_ready_user_tasks()[0]
form_data = {
"invoice.contibutorName": "Elizabeth",
"invoice.contributorId": 100,
"invoice.invoiceId": 10001,
"invoice.invoiceAmount": "1000.00",
"invoice.dueDate": "09/30/2022",
}
ProcessInstanceService.complete_form_task(
processor, user_task, form_data, current_user
)
expected = {
"contibutorName": "Elizabeth",
"contributorId": 100,
"invoiceId": 10001,
"invoiceAmount": "1000.00",
"dueDate": "09/30/2022",
}
processor.do_engine_steps(save=True)
assert processor.get_data()["invoice"] == expected