gemeenteutrecht / bptl Goto Github PK
View Code? Open in Web Editor NEWBusiness Process Task Library - execute work units from your (BPMN) processes
Home Page: https://bptl.utrechtproeftuin.nl
Business Process Task Library - execute work units from your (BPMN) processes
Home Page: https://bptl.utrechtproeftuin.nl
ValidSign supports webhooks: https://apidocs.validsign.nl/#operation/api.callback.get
BPTL should subscribe to the webhooks to receive events about packages created via the work unit. When the package is signed, it can then send a BPMN message back to the Camunda process to let the process continue.
Implement an endpoint to handle Valid Sign callbacks. The payload looks like:
{
"name": "PACKAGE_COMPLETE",
"sessionUser": "...",
"packageId": "......",
"createdDate": "2017-05-02T20:17:58.408Z"
}
Implement a page to set up the Valid Sign webhook subscription. It looks like the relevant event(s) are: PACKAGE_COMPLETE
Documentation used: https://apidocs.validsign.nl/validsign_integrator_guide.pdf, page cxliv (144)
Camunda often throws HTTP 500 errors if the process execution cannot continue because of mistakes in the process model.
Possibly the response body contains more information than what we currently extract and show. We must see if we can get more info and add it to the BPTL error information.
Tasks are considered to be the smallest units that a worker will perform. A task performs a set of actions that make up a logical unit.
Camunda has the ability to define external tasks, which have topics. We expect different organizations to use different topics for the same thing, so this must be configurable on our end.
A Django app tasks
with a Task
model would need at least:
Task model with fields:
topic
An initial ZGW task to create a zaak:
A secondary task is to set a particular status for a zaak
There should be a work unit to set a rol for a zaak, mapping to the rol_create
operation.
Input parameters for the task:
zaakUrl
: the URL reference of the zaak to create a rol foromschrijving
: the roltype omschrijving, use this in combination with zaak.zaaktype
to find the correct rolType
referencebetrokkene
: a JSON object containing the rest of the body for rol_create
In bptl.work_units.zgw.tasks.zaak.CreateZaakTask.create_rol
you can see an existing implementation that gets you there 90% of the way.
zaakUrl
and omschrijving
should be used to complete the rest of the body betrokkene
to POST to the API.
Upstream issue: https://github.com/GemeenteUtrecht/ZGW/issues/518
Upstream issue: https://github.com/GemeenteUtrecht/ZGW/issues/513
There should be BPTL tasks/work units to "freeze" a document by locking it, and also a task to unlock it again after locking it.
Acceptance criteria:
services
variable with credentialsservices
variable with credentialsOften, process variables will contain information that needs to be mapped to attributes of a Zaak, Status, Document...
It would be convenient to have a mapper interface where process variables can be specified that map directly into attributes.
In a second iteration, we can add transformations to this, such as adding a prefix or merging multiple variables into a single attribute.
Adding (a set of) mappers to a task would then first run the mappers as part of the task to set the correct variables.
So I can add a Toelichting when I set a new status.
https://github.com/GemeenteUtrecht/bptl/blob/master/src/bptl/work_units/zgw/tasks/zaak.py#L121
First pass: we use the integration from Contezza.
Webscripts documentation: see https://github.com/GemeenteUtrecht/ZGW/issues/540#issuecomment-726762996
Utrecht webscript index - https://alfresco.utrechtproeftuin.nl/alfresco/s/index/family/xential
Two flows:
Input task variables:
nodeRef
templateUuid
filename
templateVariables
(JSON)Output:
buildId
(if available)xentialTemplateUrl
(if available)Currently task documentation is mostly visible via the /taskmappings
endpoint, which poses a number of problems:
One of the goals is to have BPTL documentation available for non-technical people so they get an idea of which generic building blocks are available. A grouping of the tasks per topic/domain (the python packages are already structured this way!) in the presentation layer would provide a first improvement.
Other improvements are:
A new documentation section should facilitate this. We can add this to the existing setup and gradually replace existing pages.
Acceptance criteria:
Nice to have:
Improved documentation parsing/system to document work units. A decorator-like approach could be viable, something like:
@register
@task.variable("zaakUrl", "URL reference to the zaak", required=True, type=str)
def example_task(task: BaseTask):
do_stuff()
return {}
but this could also be handled by function ArgSpec
s or other formats (Sphinx arg docs for example).
After requesting to Xential to build a document, the status of the build can be retrieved through a call to the endpoint:
/document/{document_id}
. The process should be configured to check for the status. In the case where the response reports that an error has occurred, this should terminate the process.
To do:
There should be some functionality to request the available templates from Xential.
The approach on how to do this is TBC.
When a silent document is built, all template variables need to be submitted to Xential when creating a ticket.
These are currently passed to BPTL as task variables, but no check is done to see if all of them are present.
To Do
Request from Xential which template variables a template needs and then check that they match those in the task variables. This will require the new Xential endpoint for retrieving template variables.
Results contain more information than just URLs, to be able to quickly relay feedback. For consistency purposes, after #39, the other work units should be updated.
Xential provide document creation tools, based on the principle of document templates combined with template variables as input. This templating action can be done in the background as a "silent" template or interactively by an end-user filling out the required fields/variables.
The Documenten API is well-known and part of the standard for API's voor Zaakgericht Werken.
Combining all of this in BPTL should lead to the following flow:
As an administrator, I need a custom admin view on /admin/xential/templates
that fetches the templates from Xential API endpoint and displays the name + UUID so that I can copy the UUID from there
The BPTL work unit creates a document in the Documenten API after it has been built in Xential. In order to do this, it needs to provide the required fields for a Enkelvoudiginformatieobject
to the API.
Currently these fields are expected to be present in the process variable of the task, but no explicit checks are present.
To do
Check that all the required fields have been passed to the task and return an error if they are not. This should happen before the process of building a ticket starts.
It seems that this week Xential updated the API and the following issues were seen:
Het document kan niet worden opgeslagen. Er is geen opslagpad gedefinieerd.
java.lang.RuntimeException: nl.interactionnext.builder.BuilderException: nl.interactionnext.xutil.exceptions.LocalizedException: There is no storage path defined in the manager.
at nl.interactionnext.builder.DocumentBuilder.doBuildJob(DocumentBuilder.java:255)
at nl.interactionnext.builder.BuildJob$BuildJobCallable.call(BuildJob.java:53)
at nl.interactionnext.builder.BuildJob$BuildJobCallable.call(BuildJob.java:35)
at nl.interactionnext.xutil.concurrent.ThreadContextUtil.doContextualized(ThreadContextUtil.java:110)
at nl.interactionnext.xutil.events.ThreadContextAwareCallableWrapper.call(ThreadContextAwareCallableWrapper.java:26)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at nl.interactionnext.xutil.work.v3.Job$1.run(Job.java:63)
at nl.interactionnext.xutil.work.v3.JobExecutorThread.runJob(JobExecutorThread.java:89)
at nl.interactionnext.xutil.work.v3.JobExecutorThread.run(JobExecutorThread.java:65)
Caused by: nl.interactionnext.builder.BuilderException: nl.interactionnext.xutil.exceptions.LocalizedException: There is no storage path defined in the manager.
at nl.interactionnext.builder.AbstractBuilder.buildAndRegisterDocument(AbstractBuilder.java:99)
at nl.interactionnext.builder.DocumentBuilder.doBuildJob(DocumentBuilder.java:180)
... 8 more
Caused by: nl.interactionnext.xutil.exceptions.LocalizedException: There is no storage path defined in the manager.
at nl.interactionnext.dms.fs.filebaseddms.FileBasedDMSRegistration.getStoragePath(FileBasedDMSRegistration.java:171)
at nl.interactionnext.dms.fs.filebaseddms.FileBasedDMSRegistration.sendFileToDMS(FileBasedDMSRegistration.java:101)
at nl.interactionnext.dms.DMSRegistration.addFile(DMSRegistration.java:88)
at nl.interactionnext.builder.DMSRegistrator.addMimeTypes(DMSRegistrator.java:130)
at nl.interactionnext.builder.DMSRegistrator.registerDocument(DMSRegistrator.java:83)
at nl.interactionnext.builder.AbstractDocument.register(AbstractDocument.java:46)
at nl.interactionnext.builder.AbstractBuilder.buildAndRegisterDocument(AbstractBuilder.java:93)
... 9 more
Currently, the create zaak work unit requires the zaaktype URL to create the zaak. This has a couple of drawbacks:
A similar problem exists for the setting of the zaak result where the resultaattype URL must be specified in the process model.
We can change the work units to accept parameters that can be used to look up these values instead, using the Catalogi API.
For the zaaktype, this means that we can use the combination of zaaktype.identificatie
, catalogus.rsin
and catalogus.domein
. For resultaattype, we should be able to use resultaattype.omschrijving
.
Tasks
CreateZaakTask
work unit
zaaktype
variable optionalzaaktypeIdentificatie
, catalogusRSIN
and catalogusDomein
variables. catalogusRSIN
can default to the organisatieRSIN
variable (so it's an optional variable).zaaktype
(url) or (zaaktypeIdentificatie
and catalogusDomein
) are required. If all of them are provided, zaaktype
is prioritised as it's the most explicit.catalogusRSIN
and catalogusDomein
, look up the relevant catalogus in the API (see https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/VNG-Realisatie/catalogi-api/1.1.0/src/openapi.yaml#operation/catalogus_list)zaaktypeIdentificatie
, resolve the zaaktype (using https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/VNG-Realisatie/catalogi-api/1.1.0/src/openapi.yaml#operation/zaaktype_list)zaaktype.beginGeldigheid
and zaaktype.eindeGeldigheid
for this)CreateResultaatTask
and CloseZaakTask
work units
omschrijving
variable is supported. If both omschrijving
and resultaattype
are specified, the latter wins as it is more specificomschrijving
is provided, retrieve the resultaattypen of the zaak.zaaktype (using https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/VNG-Realisatie/catalogi-api/1.1.0/src/openapi.yaml#operation/resultaattype_list) and select the correct one based on resultaattype.omschrijving
. For practical reasons, I think we can ignore the upper/lower case here (unless you would have multiple hits, then BPTL should throw an error).While implementing #8, we receive back tasks from different topics. While we can loop over all known topics and fetch and lock tasks like that, it's probably more robust to set up a task router based on topic that knows where to send tasks for further processing.
Hooking that into celery tasks/workers will then provide sufficient scaling options.
After BPTL has made a POST request to the Documenten API to store the newly created Xential document, the new URL of the document should be added to the process variables.
Documentation of messages in camunda and process variables:
https://docs.camunda.org/manual/7.14/reference/rest/message/post-message/
Set up the project boilerplate using https://bitbucket.org/maykinmedia/default-project/src/master/
Python 3.8 and Django 3.0 are okay, if we run into problems, we downgrade to Django 2.2 and possibly Python 3.7
Celery's basic config is having a single queue named celery
where all jobs are submitted.
Since the introduction of long polling to Camunda in 6d03a3d this introduces a risk - if the prefetch multiplication is mis-configured, tasks that should run instantly can be queued inside of a worker behind a long-poll task (which may run for up to 10 minutes in its current config).
To prevent mistakes like that (and being able to ACK early) - it makes sense to have two queues:
This also means that workers must be spun up/assigned to a particular queue (by default they listen to all queues).
The desired configuration YAML in infrastructure should look like:
django_app_k8s_celery_workers:
- queue: celery
replicas: 3
- queue: long-polling
replicas: 2
Acceptance criteria:
celery
queueCurrent issues:
Current direction of solution:
Application currently handling the process sets a variable: getCredentialsUrl
.
This should be a URL that is impossible to guess, and ideally be based around a hash of some attribute that changes when accessed/when credentials have been obtained -> we want to prevent replay attacks. Possibly BPTL itself needs to be authorized to the application URL out of band with a static token.
Whenever BPTL needs credentials, it makes a POST request:
POST /${getCredentialsUrl} HTTP/1.1
{"api": "https://example.com/api/v1/"}
The application replies with the relevant headers required, e.g.:
{"header": "Authorization", "value": "Bearer <some-jwt>", "api": "https://example.com/api/v1/"}
BPTL uses those credentials to make the required API calls
Whenever other applications take over for the process, they can set their own getCredentialsUrl
process variable to indicate that their credentials should now be used (relevant for audit logs!).
This solves:
There are currently 2 endpoints:
For endpoint 2. this can be done using token in a similar way to:
https://github.com/GemeenteUtrecht/zac-lite/blob/main/backend/src/zac_lite/user_tasks/tokens.py
https://github.com/GemeenteUtrecht/zac-lite/blob/main/backend/src/zac_lite/user_tasks/tests/test_token_invalidation.py
20-May-2021 13:47:12.408 SEVERE [http-nio-8080-exec-23] org.camunda.commons.logging.BaseLogger.logError ENGINE-16004 Exception while closing command context: ENGINE-13031 Cannot correlate a message with name 'documentCreated' to a single execution. 2 executions match the correlation keys: CorrelationSet [businessKey=null, processInstanceId=db97972b-b971-11eb-9bee-2a3de7ed312a, processDefinitionId=null, correlationKeys=null, localCorrelationKeys=null, tenantId=null, isTenantIdSet=false]
org.camunda.bpm.engine.MismatchingMessageCorrelationException: ENGINE-13031 Cannot correlate a message with name 'documentCreated' to a single execution. 2 executions match the correlation keys: CorrelationSet [businessKey=null, processInstanceId=db97972b-b971-11eb-9bee-2a3de7ed312a, processDefinitionId=null, correlationKeys=null, localCorrelationKeys=null, tenantId=null, isTenantIdSet=false]
Variables are more often structured than not (simple primitive strings/numbers vs. JSON objects), which can/should be validated using DRF serializers or an implementation on top of that.
It's important that:
Probably a 1.1.0 feature, wouldn't let this block a 1.0 release.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.