Skip to content

Commit

Permalink
Add ZGW app that can replicate a Signal to an external case managemen…
Browse files Browse the repository at this point in the history
…t system
  • Loading branch information
bartjkdp committed Mar 14, 2023
1 parent e6c390e commit 0a39c73
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 1 deletion.
2 changes: 1 addition & 1 deletion app/signals/apps/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2018 - 2021 Gemeente Amsterdam
# Copyright (C) 2022 Delta10 B.V.
2 changes: 2 additions & 0 deletions app/signals/apps/zgw/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
24 changes: 24 additions & 0 deletions app/signals/apps/zgw/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
from django.contrib import admin

from .models import Case


@admin.register(Case)
class EmailTemplate(admin.ModelAdmin):
list_display = [
'_signal',
'external_id'
]

readonly_fields = [
'_signal',
'external_id'
]

def has_add_permission(self, request, obj=None):
return False

def has_delete_permission(self, request, obj=None):
return False
12 changes: 12 additions & 0 deletions app/signals/apps/zgw/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
from django.apps import AppConfig


class ZgwConfig(AppConfig):
name = 'signals.apps.zgw'
verbose_name = 'Replication to case management system'
default_auto_field = 'django.db.models.BigAutoField'

def ready(self):
from . import signal_receivers # noqa
29 changes: 29 additions & 0 deletions app/signals/apps/zgw/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
# Generated by Django 3.2.15 on 2022-10-24 21:35
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('signals', '0162_signal_user_HISTORY'),
]

operations = [
migrations.CreateModel(
name='Case',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('external_id', models.CharField(db_index=True, max_length=100)),
('_signal', models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name='zgw_case',
to='signals.signal'
)),
],
),
]
2 changes: 2 additions & 0 deletions app/signals/apps/zgw/migrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
19 changes: 19 additions & 0 deletions app/signals/apps/zgw/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
from django.db import models

from signals.apps.signals.models import Signal


class Case(models.Model):
"""Relate a Signal to a case in an external system"""
_signal = models.OneToOneField(
Signal,
related_name='zgw_case',
on_delete=models.CASCADE,
)

external_id = models.CharField(max_length=100, db_index=True)

def __str__(self):
return str(self._signal.id)
20 changes: 20 additions & 0 deletions app/signals/apps/zgw/signal_receivers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
from django.conf import settings
from django.dispatch import receiver

from signals.apps.signals.managers import create_initial, update_status

from . import tasks


@receiver(create_initial, dispatch_uid='zgw_create_initial')
def create_initial_handler(sender, signal_obj, *args, **kwargs):
if settings.ZGW_API_URL:
tasks.create_initial.delay(signal_id=signal_obj.pk)


@receiver(update_status, dispatch_uid='zgw_update_status')
def update_status_handler(sender, signal_obj, status, *args, **kwargs):
if settings.ZGW_API_URL:
tasks.update_status.delay(status_id=status.pk)
94 changes: 94 additions & 0 deletions app/signals/apps/zgw/tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# SPDX-License-Identifier: MPL-2.0
# Copyright (C) 2022 Delta10 B.V.
from urllib.parse import urljoin

import requests
from django.conf import settings
from django.template.loader import render_to_string
from django.utils.timezone import localtime

from signals.apps.signals.models import Signal, Status
from signals.apps.signals.workflow import AFGEHANDELD, GEANNULEERD, GEMELD, HEROPEND
from signals.celery import app

from .models import Case

MAX_RETRIES = 10
DEFAULT_RETRY_DELAY = 60*10

AUTORETRY_FOR = (
requests.exceptions.Timeout,
requests.exceptions.ConnectionError,
requests.exceptions.HTTPError
)


@app.task(autoretry_for=AUTORETRY_FOR, max_retries=MAX_RETRIES, default_retry_delay=DEFAULT_RETRY_DELAY)
def create_initial(signal_id):
signal = Signal.objects.get(pk=signal_id)

context = {
'signal': signal,
'url': urljoin(settings.FRONTEND_URL, f'/manage/incident/{signal.id}'),
}

einddatumGepland = signal.created_at.strftime('%Y-%m-%d')
if signal.category_assignment:
einddatumGepland = localtime(signal.category_assignment.deadline).strftime('%Y-%m-%d')

data = {
'bronorganisatie': settings.ZGW_BRONORGANISATIE,
'omschrijving': render_to_string('case_description.txt', context=context),
'toelichting': render_to_string('case_explanation.html', context=context),
'zaaktype': settings.ZGW_ZAAKTYPE,
'registratiedatum': localtime(signal.created_at).strftime('%Y-%m-%d'),
'tijdstipRegistratie': localtime(signal.created_at).strftime('%Y-%m-%d %H:%M'),
'verantwoordelijkeOrganisatie': settings.ZGW_VERANTWOORDELIJKE_ORGANISATIE,
'startdatum': localtime(signal.created_at).strftime('%Y-%m-%d'),
'einddatumGepland': einddatumGepland,
'kenmerken': [
{
'kenmerk': signal.get_id_display(),
'bron': 'SIGNALEN'
}
]
}

url = urljoin(settings.ZGW_API_URL, '/zgw/zaken')
response = requests.post(url, json=data, timeout=int(settings.ZGW_TIMEOUT))
response.raise_for_status()

case = response.json()

Case.objects.update_or_create(external_id=case['uuid'], defaults={
'_signal': signal
})

# Trigger async job to set current status of Signal
app.send_task('signals.apps.zgw.tasks.update_status', args=[signal.status.pk])


@app.task(autoretry_for=AUTORETRY_FOR, max_retries=MAX_RETRIES, default_retry_delay=DEFAULT_RETRY_DELAY)
def update_status(status_id):
status = Status.objects.get(pk=status_id)
signal = status._signal

if not hasattr(signal, 'zgw_case'):
return # this Signal is not registered in an external case management system

zgw_states = {
GEMELD: settings.ZGW_STATUS_RECEIVED,
HEROPEND: settings.ZGW_STATUS_RECEIVED,
AFGEHANDELD: settings.ZGW_STATUS_DONE,
GEANNULEERD: settings.ZGW_STATUS_DONE
}

data = {
'zaak': signal.zgw_case.external_id,
'statustype': zgw_states[status.state],
'datumStatusGezet': localtime(status.created_at).strftime('%Y-%m-%d')
}

url = urljoin(settings.ZGW_API_URL, '/zgw/statussen')
response = requests.post(url, json=data, timeout=int(settings.ZGW_TIMEOUT))
response.raise_for_status()
1 change: 1 addition & 0 deletions app/signals/apps/zgw/templates/case_description.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ signal.category_assignment.category.name }} - {{ signal.get_id_display }}
1 change: 1 addition & 0 deletions app/signals/apps/zgw/templates/case_explanation.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bekijk voor meer informatie <a href="{{ url }}" target="_blank">{{ url }}</a>
11 changes: 11 additions & 0 deletions app/signals/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
'signals.apps.dataset',
'signals.apps.questionnaires',
'signals.apps.my_signals',
'signals.apps.zgw',
'logs'
]

Expand Down Expand Up @@ -335,6 +336,16 @@ def is_super_user(user):
SIGMAX_CLIENT_KEY = os.getenv('SIGMAX_CLIENT_KEY', None)
SIGMAX_SEND_FAIL_TIMEOUT_MINUTES = os.getenv('SIGMAX_SEND_FAIL_TIMEOUT_MINUTES', 60*24) # noqa Default is 24hrs.

# ZGW settings
ZGW_API_URL = os.getenv('ZGW_API_URL', '')
ZGW_AUTH_TOKEN = os.getenv('ZGW_AUTH_TOKEN', '')
ZGW_BRONORGANISATIE = os.getenv('ZGW_BRONORGANISATIE', '')
ZGW_VERANTWOORDELIJKE_ORGANISATIE = os.getenv('ZGW_VERANTWOORDELIJKE_ORGANISATIE', '')
ZGW_ZAAKTYPE = os.getenv('ZGW_ZAAKTYPE', '')
ZGW_STATUS_RECEIVED = os.getenv('ZGW_STATUS_RECEIVED', '')
ZGW_STATUS_DONE = os.getenv('ZGW_STATUS_DONE', '')
ZGW_TIMEOUT = os.getenv('ZGW_TIMEOUT', 10)

# Child settings
SIGNAL_MAX_NUMBER_OF_CHILDREN = 10

Expand Down

0 comments on commit 0a39c73

Please sign in to comment.