Git Product home page Git Product logo

open-klant's Introduction

Open Klant

Version

2.0.0

Source

https://github.com/maykinmedia/open-klant

Keywords

klanten, klantinteracties, contactmomenten, api, common ground

License

EUPL

Documentation Status Docker image

Registratiecomponent voor de opslag en ontsluiting van klantgegevens volgens de Klantinteracties API-specificatie. (English version)

Ontwikkeld door Maykin B.V. in samenwerking met gemeente Amsterdam, gemeente Den Haag, gemeente Utrecht en VNG Realisatie.

Introductie

Open Klant implementeert de (concept) Klantinteracties API specificatie van VNG welke een beperkte set aan gegevens over klanten en hun interactie met de gemeente kan opslaan en ontsluiten.

Samen met gemeenten, die volop bezig zijn met de implementatie van Common Ground, en VNG, wordt gewerkt aan standaardisatie van de API en realisatie van Open Klant als beproeving van de toekomstige API standaard.

API specificatie

Hieronder staat de versie van Open Klant en welke versie van de API-specificatie wordt aangeboden.

Open Klant versie API versie Release datum API specificatie

master/latest

n/a

n/a

ReDoc, Swagger

2.0.0

0.0.3

2024-03-15

ReDoc, Swagger

1.0.0

0.0.1

2023-08-05

Klanten: ReDoc, Swagger Contactmomenten: ReDoc, Swagger

Vorige versies worden nog 6 maanden ondersteund nadat de volgende versie is uitgebracht. Open Klant versie 1.0.0 bevat nog de Klanten en Contactmomenten API-specificatie die door VNG is geschrapt en beschouwd moet worden als legacy.

Zie: Alle versies en wijzigingen

Ready-to-go implementatie

Build status Coverage Code style CodeQL scan Code style Supported Python version

Deze implementatie is bedoeld als referentie implementatie van de API specificaties maar tevens een productiewaardig component dat ingezet kan worden in het ICT landschap van de overheid.

Quickstart

  1. Download en start Open Klant:

    $ wget https://raw.githubusercontent.com/maykinmedia/open-klant/master/docker-compose.yml
    $ docker-compose up -d --no-build
    $ docker-compose exec web src/manage.py loaddata klantinteracties contactgegevens
    $ docker-compose exec web src/manage.py createsuperuser
  2. In de browser, navigeer naar http://localhost:8000/ om de beheerinterface en de API te benaderen.

Licentie

Copyright © Maykin B.V., 2023 - 2024

Licensed under the EUPL

open-klant's People

Contributors

alextreme avatar annashamray avatar bart-maykin avatar bartvaderkin avatar charstring avatar erhancitil avatar joeribekker avatar nath82 avatar nathanaelgey avatar stevenbal avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

nath82 wowebnl

open-klant's Issues

Als koploper wil ik een `Betrokkene bij klantcontact` kunnen registreren

Requires #62

Informatiemodel:
image

  • Add model Betrokkene (which implements "Betrokkene bij klantcontact"
  • Add FK in Betrokkene to Klantcontact (null=False because it's a required relation, set help-text to 'Klantcontact' had 'Betrokkene bij klantcontact')
  • Add FK in Partij to Betrokkene (null=True since it's optional, set help-text to 'Betrokkene bij klantcontact' was 'Partij')

Als Erfpacht-ontwikkelaar wil ik graag meer persoonsgegevens opslaan bij klanten

.. zodat ik ook personen kan benaderen die niet in de BRP staan.

In overeenstemming met het uitgangspunt "We maken geen kopie van gegevens uit de BRP" gaat dit dus enkel over persoonsgegevens waarvan de persoon niet in de BRP staat. De API kan een validatie maken dat als er een BSN bekend is, dat deze gegevens niet mogen worden opgeslagen.

Aangeleverde lijst attributen:

  • Klantnummer (verplicht)

Natuurlijk persoon (allemaal optioneel):

  • Geboortedatum (overlapt #70)
  • Geslachtsnaam (reeds aanwezig)
  • Geslacht
  • Voorvoegsel (reeds aanwezig)
  • Voornamen (reeds aanwezig)
  • Burgerservicenummer (deze is er dus niet)
  • Verblijfplaats__postcode
  • Verblijfplaats__huisnummer
  • Verblijfplaats__straat

Organisaties (allemaal optioneel)

  • KVK nummer(deze is er dus niet)
  • RSIN (deze is er dus niet)
  • Handelsnaam (=naam?)
  • Straatnaam
  • Huisnummer
  • Huisnummertoevoeging
  • Postcode
  • Plaats
  • Type

Discuss

  • Een aantal attributen zijn "reeds aanwezig" (zie boven) maar deze hebben een andere intentie dan BRP-achtige gegevens opslaan voor mensen die niet in de BRP staan. Ze moeten dus dubbel?
  • VNG akkoord?
  • Koplopers akkoord?

Als koploper wil ik een `Partij`en kunnen registreren

Information model:

See here for all definitions: https://vng-realisatie.github.io/klantinteracties/informatiemodel/gegevenswoordenboek

Assuming this is the start of the model-creation:

  • Add component folder, and add klantinteracties module

As for the actual models:

  • Add model Partij and add all Partij attributes as fields to the model:
    • As field-type (CharField, URLField) please search in the above page for "Attribuutsoort details ". If not found, look further or ask Joeri
    • Use lowercase attribute-name for fieldname
    • Add help-text as described in "gegevenswoordenboek"
    • Mark field as required when column Card is marked as 1 and don't make it required when it says 0..1
    • Make sure to add all attributes as fields that are in the grey groups, since they represent groups of information (2 attributes at the bottom). See: https://github.com/open-zaak/open-zaak/blob/8ca80400cad55a56574ce41663edfcff080aaf7a/src/openzaak/components/zaken/models/zaken.py#L422 (note how all these attributes are part of the same model but grouped with that construction.
  • Add model Persoon + FK to Partij
  • Add model Contactpersoon + FK to Partij
  • Add model Organisatie + FK to Partij

I only added the subtasks for Partij, but they also hold for the other models ofcourse.

Als koploper wil ik de aanschrijfnaam automatisch afgeleid hebben

.. zodat ik dit niet hoef samen te stellen op basis van andere attributen.

Aangezien deze ontbreekt in de BRP voegen we enkel het read-only attribuut "volledigeNaam" toe. Deze wordt opgebouwd uit <voornamen> <voorvoegsel> <geslachtsnaam>. Het geslacht wordt NIET meegenomen omdat in de BRP dit blijkbaar enkel wordt gedaan icm adelijke titels die we hier niet opnemen.

Tasks

  • Add readonly field "volledigeNaam" that displays: <voornamen> <voorvoegsel> <geslachtsnaam>

Achtergrond

Uit Excel:
image

Blocked
VNG heeft aangegeven dit (Aanschrijfnaam) nader uit te werken.

Als KISS-ontwikkelaar wil ik kunnen zoeken/filteren op personen die wel/niet in de BRP staan

.. zodat ik goed onderscheid kan maken tussen diverse type partijen.

Het is wenselijk om bij het opvragen van gegevens aan te kunnen geven of je gegevens wil van de BRP-klanten en/of de niet-BRP-klanten. In bepaalde situaties is dat onderscheid relevant.
Dit zou bijvoorbeeld gefaciliteerd kunnen worden, door het mogelijk te maken om op lege velden te zoeken. Dat is volgens mij in de huidige API (Open Klant v0, red.) niet mogelijk. We kunnen nu dus nog niet klanten opvragen waarvan de BSN leeg is, als we alleen geïnteresseerd zijn in niet-BSN-klanten.

Als Erfpacht/KISS-ontwikkelaar wil ik een register voor personen/bedrijven die niet in de BRP/RNI/KvK zitten

.. zodat ik hen kan contacten.

Het overleg ticket #71 heeft geleidt tot de volgende insteek: Er komt een nieuwe API voor Contactgegevens, naast Klantinteracties. De Contactgegevens API is een niet gestandaardiseerde API voor de opslag van gegevens die nodig zijn voor "partijen" die niet in de BRP, RNI of KvK zitten.

Welkom Contactgegevens API. Deze API zal volgens dezelfde uitgangspunten worden opgesteld als de Klantinteracties API en NL API strategie, voor maximale herkenbaarheid en compatibiliteit.

  • Voeg een nieuwe component module toe contactgegevens
  • Voeg model Contactgegevens toe.
  • Voeg model Organisatie toe, die met een FK naar Contactgegevens wijst + alle attributen hieronder
  • Voeg model Persoon toe, die met een FK naar Contactgegevens wijst + alle attributen hieronder

Nader uit te werken:

  • Contactgegevens wijst via een FkOrUrlField naar PartijIdentificator

Ik pas de lijst uit #71 aan om in overeenstemming te zijn met de BRP voor mensen in het buitenland. Ik hanteer hetzelfde voor bedrijven omdat de KvK enkel adressen in NL kan bevatten. Let op dat dit Adres een soort evenknie is van de KvK/BRP en wellicht niet gebruikt wordt, immers, Correspondentieadres en Bezoekadres zijn al bij Partij aanwezig.

Attributen Persoon

  • Geboortedatum (zie voor achtergrondinformatie #70)
  • Overlijdensdatum (zie voor achtergrondinformatie #70)
  • Geslachtsnaam
  • Geslacht__code (gegevensgroep geslacht)
  • Voorvoegsel
  • Voornamen
  • Adres (gegevensgroep):
  • Adres__adresregel1
  • Adres__adresregel2
  • Adres__adresregel3
  • Adres __land (gegevensgroep)
  • Land__code

Zie: https://brp-api.github.io/Haal-Centraal-BRP-bevragen/v2/redoc#tag/Personen/operation/Personen

Attributen Organisatie

  • Handelsnaam
  • Oprichtingsdatum
  • Opheffingsdatum
  • Adres (gegevensgroep):
  • Adres__adresregel1
  • Adres__adresregel2
  • Adres__adresregel3
  • Adres__land (gegevensgroep)
  • Land__code

Zie: https://developers.kvk.nl/documentation/basisprofiel-api (indien er geen lengtes staan, hanteer die van de BRP)

Github Actions for CI

Similar to Open Zaak, though less complex

  • Code quality (black/isort/flake8)
  • Run Django testsuite
  • Generate schema
  • Docker build/push

Caching errors while trying to log in

After deploying open-klant 0.1.0 on a kubernetes 1.23.12 cluster the application starts without issues. When trying to login with a (newly created) superuser account it throws the following exception when logging in.

2023-01-25 12:26:35,653 ERROR django.request Internal Server Error: /admin/login/ Traceback (most recent call last): File "/usr/local/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner response = get_response(request) File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) File "/usr/local/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func response = view_func(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/contrib/admin/sites.py", line 399, in login return LoginView.as_view(**defaults)(request) File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view return self.dispatch(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 45, in _wrapper return bound_method(*args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/views/decorators/debug.py", line 76, in sensitive_post_parameters_wrapper return view(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 45, in _wrapper return bound_method(*args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 142, in _wrapped_view response = view_func(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/utils/decorators.py", line 45, in _wrapper return bound_method(*args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func response = view_func(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/views.py", line 61, in dispatch return super().dispatch(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/views/generic/base.py", line 97, in dispatch return handler(request, *args, **kwargs) File "/usr/local/lib/python3.8/site-packages/django/views/generic/edit.py", line 142, in post return self.form_valid(form) File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/views.py", line 90, in form_valid auth_login(self.request, form.get_user()) File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/__init__.py", line 108, in login request.session.cycle_key() File "/usr/local/lib/python3.8/site-packages/django/contrib/sessions/backends/base.py", line 297, in cycle_key self.create() File "/usr/local/lib/python3.8/site-packages/django/contrib/sessions/backends/cache.py", line 50, in create raise RuntimeError( RuntimeError: Unable to create a new session key. It is likely that the cache is unavailable

Als Erfpacht-ontwikkelaar wil ik persoonlijke communicatie instellingen opslaan

..zodat ik bijvoorbeeld niet over alles benaderd wordt.

Deze user story komt voort uit de hackathon rondom MijnZaken/notificeren, waarin in diverse presentaties iets werd gezegd over wanneer wel/niet een bericht sturen, en naar welk kanaal/specifieke (digitale) adres.

Het is niet duidelijk of dit in deze API moet komen maar het is wel gerelateerd, dus voer voor discussie.

Discuss

  • Moet er een functie in de API komen om voorkeuren op te slaan rondom notificeren? Bijvoorbeeld: Voor zaken in domein Wonen: E-mail naar [email protected]; Voor taken: SMS naar 0612345678

Als projectmanager wil ik dat het resources ontsloten wordt via een CRUD API

.. zodat de API een eerste werkbare versie heeft. CRUD voorziet in alle operaties zonder dat deze geoptimaliseerd zijn voor gebruik.

Het gaat om de volgende resoures:

  • Actor
  • GeautomatiseerdeActor
  • Medewerker
  • OrganisatorischeEenheid
  • DigitaalAdres
  • InterneTaak
  • Klantcontact
  • Betrokkene
  • Onderwerpobject
  • Bijlage
  • Partij
  • Organisatie
  • Persoon
  • Contactpersoon
  • PartijIdentificator

Add documentation for the ReDoc:

  • Actor
  • GeautomatiseerdeActor
  • Medewerker
  • OrganisatorischeEenheid
  • DigitaalAdres
  • InterneTaak
  • Klantcontact
  • Betrokkene
  • Onderwerpobject
  • Bijlage
  • Partij
  • Organisatie
  • Persoon
  • Contactpersoon
  • PartijIdentificator

Als projectmanager wil ik autorisaties op de API hebben

... zodat enkel geautoriseerde clients er bij kunnen.

Tasks

  • Add token authorization (see Objects API) in its simplest form. A token provides access to the entire API, both read and write so no distinction.

Achtergrond

Maykin:

Ik wil eigenlijk voor deze API dezelfde authenticatie gebruiken als voor de Objecten API: Een API-key. Dit heeft een aantal redenen: 1) Veel eenvoudiger, 2) Anders moeten we de Autorisaties API aanpassen (en dat moet via Michiel), 3) Gemeenten leggen vaak ook nog wel hun eigen gateway-autorisaties / OPA-mechanisme er bovenop.

VNG:

Hier doen wij vooralsnog geen uitspraken over. Lijkt mij dus een implementatie-keuze.

Add celery for notification support

The latest version of Open Klant does have notifications-api-common however the project doesn't have celery enabled so it most likely won't send out notifications with the v0.2 version.

Als koploper wil ik een `Actor` kunnen registreren

Information model:
image

  • Add model Actor
  • Add M2M from Klantcontact to Actor (null=False, blank=False, had betrokken)
  • Add model GeautomatiseerdeActor + FK to Actor
  • Add model Medewerker + FK to Actor
  • Add model OrganisatorischeEenheid + FK to Actor

Als projectmanager wil ik een nummergenerator voor functionele nummers in de API

..zodat ik niet zelf de nummers hoef te genereren.

Tasks

  • Everywhere where there is a "nummer"-attribute, this should automatically get a human friendly number if it is left empty.
  • We can simply make this an incremental number that starts at 1 by doing aggregate(models.Max("nummer"))["nummer__max"] + 1 in the save method and make the transaction atomic.

Uiteindelijk gaan we waarschijnlijk naar: https://github.com/maykinmedia/commonground-api-common/blob/9c1c538705cf6b4f4b024779e3e91805b287b01d/vng_api_common/utils.py#L208

maar dan moet deze goedgekeurd worden: VNG-Realisatie/klantinteracties#273

Verder is dit een invulling van: VNG-Realisatie/klantinteracties#242

Achtergrond

Kijk even naar Open Zaak hiervoor, maar het formaat mag zonder context, dus gewoon een integer maar dan oplopend. Ik zou de "nummer" velden het liefst strings maken, zodat we voorloopnullen kunnen hebben. Even met VNG overleggen.

In Open Zaak is er een aparte tabel om race-condities te voorkomen. Dat moet hier ook.

Als koploper wil ik aanvullingen op `Partij` die nog niet in het informatiemodel van VNG zitten

.. zodat ik mijn praktische use case kan invullen.

Opgevoerd bij VNG: VNG-Realisatie/klantinteracties#272

Tasks

  • Add model Categorie with fields:
  • naam (charfield, max_length=80)
  • beginDatum (datefield, default=creation date if empty/not provided in API-call)
  • eindDatum (datefield, default=None)
  • Add FK from Categorie to Partij (null=True)
  • Add model to admin (as inline of Partij)
  • Add as read-only inline array to Partij
  • Make sure the resource description says: "Let op: Dit endpoint is EXPERIMENTEEL." en hetzelfde geldt bij de description van de read-only inline bij Partij: "Let op: Dit attribuut is EXPERIMENTEEL."

Update op taken:

In retrospect, you can link a category with start/end date per party, so we need to refactor a bit.

  • Add new model, CategorieRelatie met API resource, marked with "EXPERIMENTEEL" like above.
  • Move the fields to this new model:
    • beginDatum (datefield, default=creation date if empty/not provided in API-call)
    • eindDatum (datefield, default=None)
  • Add FK from CategorieRelatie to Categorie (null=True)
  • Add FK from CategorieRelatie to Partij to Partij (null=True)
  • Remove the FK from Category to Partij

Achtergrond

Uit Excel (1):
image

Uit Excel (2):
image

Dit stond verkeerd in de Excel (Eric) en moet niet aan Externe Identificatie maar aan Partij gekoppeld zijn.
image

  • [ ]

Discuss

  • Categorie of CategorieRelatie? -> IM model benaming. Is gewoon categorie.
  • Wat is CategorieType? Is dat een enumeratie of vrije tekst? -> Door gemeente te onderhouden lijst
  • Moet Categorie niet naam heten? Het heeft al een relatie met "Categorie" -> check
  • Wat doen we met Geldigheid ivm historische gegevens die we niet opslaan? -> een categorie heeft een levensduur en staat eigenlijk los van overige historische gegevens.
  • Wat is Looptijdtype? -> staat hieronder uitgelegd.

Als koploper wil ik een "inhoudelijke tekst" kunnen registreren

Information model (006):
image

  • Add model Onderwerpobject

    • Add FK in Onderwerpobject to Klantcontact (fieldname: wasKlantcontact, null=True, helptekst: "'Onderwerpobject' was 'Klantcontact')
    • Add FK in Onderwerpobject to Klantcontact (fieldname: klantcontact null=True`, helptekst: "'Klantcontact' ging over 'Onderwerpobject'")
  • Add model Bijlage

    • Add FK in Bijlage to Klantcontact (null=True, helptekst="'Klantcontact' omvatte 'Bijlage")

Ik worstel nog even met de gele vlakken, dus laat die maar even zitten.

Discuss

Deze punten zijn behandeld op basis van IM 004 en verwerkt in IM 006.

  • Het gebrek aan samenhang (er is geen directe relatie) tussen een onderwerp en inhoud zou tot verwarring kunnen leiden.
  • Het gebrek aan daadwerkelijke opslag van informatie in "inhoud" lijkt nogal tegenstrijdig.
  • Als het enkel om verwijzingen gaat, dan is een gegevensgroep met deze informatie binnen Klantcontact wellicht efficiënter.
  • Moeten we Ander Object en Overig Object echt scheiden?

Polymorphic Serializers

Transform the Actor and Partij serializers into Polymorphic serializers:

Actor

Partij

  • Actor moet een polymorphisch attribuut bevatten "partijIdentificatie" dat ingevuld wordt met persoon, contactpersoon of organisatie. De inline resource "partij" kan dan uiteraard weg in de serializer
  • Kan je "soortPartij" hernoemen (enkel in de API serializer) naar "partijType" en verplaatsen naar net boven "partijIdentificatie"?
  • Persoon, Contactpersoon en Organisatie resources mogen weg.
  • Query params toevoegen: nummer, identificator+(attributen bij algemeen), indicatieActief, indicatieGeheimhouding

Als projectmanager wil ik dat de admin beschikbaar is..

..zodat ik handmatig kan ingrijpen in de gegevenslaag indien nodig.

  • Add Partij
    • List filters: soort partij, indicatie actief
    • List columns: nummer, naam (gebaseerd op persoon, contactpersoon, orgaisatie), soort partij, indicatie actief
    • Detail: See if you can show/edit persoon, contactpersoon or organisatie (as inline, or fields, or a link to the modeladmin for those models)
    • Detail add inlines for digitale adressen, voorkeurs digitale adressen en betrokkenen
  • Add Klantcontact
    • List filters: indicatie vertrouwelijk
    • List date hierarchy op plaatsgevonden op
    • List columns: nummer, kanaal, indicatie vertrouwelijk, betrokkene-naam
    • Detail add inlines for Betrokkene, Actor, Onderwerpobject, Bijlage, Interne Taak
  • Add Actor
    • See if you can show/edit medekwerker, organisatorische eenheid, geautomatiseerde actor
    • Detail add inline for: InterneTaak

I think I have everything now :)

And, be practical. The goal is to make a quick admin UI using the available admin options, not to poke around with templates and such. If you run into issue, let me know.

Minor code cleanups

  • Remove datamodel directory
  • Move tests for klanten/contactmomenten outside of api directory
  • Rework settings to be similar to Open Zaak
  • Remove deprecated files (Jenkinsfile, etc.)

Als projectmanager wil ik de oude Klanten en Contactmomenten API archiveren

... zodat deze voorlopig nog beschikbaar blijven.

  • Move Klanten en Contactmomenten apps to legacy folder within component
  • Make them available under a legacy v0 API URL
  • Update admin and move these models under a legacy group
  • Don't add migrations of any sort to move data from old models to future new models (for now, maybe later we'll make scripts or so).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.