.. _manual_logic: ====================== Dynamische formulieren ====================== Open Formulieren ondersteund krachtige regels en acties die het gedrag of de inhoud van het formulier aanpassen op basis van ingevoerde waarden door de gebruiker. Om te beginnen zijn er 2 termen die hierbij gebruikt worden, te weten: * **Regels** - Een regel beschrijft de voorwaarden waaraan voldaan moet worden. * **Acties** - Een actie beschrijft wat er veranderd moet worden in het formulier. Als een regel slaagt, dan worden de acties die erbij horen uitgevoerd. De opbouw is als volgt: **Als** ** (regel) **dan** ** (actie). **Voorbeeld** **Als** [*Persoonlijk: Geslacht*] [*is gelijk aan*] [*de waarde*] ``m`` **dan** [*wijzig de waarde van een veld*] [*Persoonlijk: Aanhef*] [*de waarde*] ``de heer`` Bovenstaand voorbeeld wijzigt de waarde van het tekstveld *Aanhef*, in de formulierstap *Persoonlijk*, naar ``de heer`` als het geselecteerde *Geslacht* ``m`` is. In het voorbeeld staat een aantal woorden tussen blokhaken ([...]). Hiermee duiden we in de documentatie aan dat dit keuzevelden zijn. Er zijn namelijk allerlei mogelijkheden om regels op te stellen en acties uit te voeren. Afhankelijk van de gekozen keuzevelden komen andere, meer of minder opties beschikbaar. .. image:: _assets/logica_voorbeeld.png :width: 100% Regels ====== De eerder genoemde **Als** ** regel is een vereenvoudigde weergave van alle onderdelen: **Als** [**] [**] [**] ** Hieronder staat per onderdeel uitgelegd wat de mogelijkheden zijn, en wat ze doen. * ** - Een veld uit een van de beschikbare formulierstappen of andere variabele. Voorbeeld: [*Persoonlijk: Geslacht*] * ** - Er zijn diverse operaties mogelijk. Niet alle operaties zijn mogelijk voor alle **: * **is gelijk aan** - De waarde van de ** is hetzelfde als de ** * **is niet gelijk aan** - De waarde van de ** is niet hetzelfde als de ** * **in** - De waarde van de ** is onderdeel van de **. De ** is hier veelal een lijst of een veld dat meerdere waarden kan bevatten. * **is groter dan** - Werkt alleen bij datum- en nummer-velden. * **is groter dan of gelijk aan** - Werkt alleen bij datum- en nummer-velden. * **is kleiner dan** - Werkt alleen bij datum- en nummer-velden. * **is kleiner dan of gelijk aan** - Werkt alleen bij datum- en nummer-velden. * ** - De *waarde* waarop de ** uitgevoerd wordt kan op verschillende manieren opgegeven of opgehaald worden. U moet daarom eerst het type waarde kiezen: * **de waarde** - Een handmatig opgegeven waarde. * **de variabele** - De waarde van een specifiek veld. * **de lijst** - Een handmatig opgegeven lijst van waarden. * **vandaag** - Alleen beschikbaar i.c.m. een datum en geeft extra opties om een berekening te maken. Standaard worden altijd alle regels getest bij het invullen van een formulier. Indien bepaalde regels pas getest moeten worden vanaf een bepaalde stap omdat er eerder ingevulde gegevens nodig zijn bijvoorbeeld, dan kan dit ingesteld worden. Klik hiervoor links van de regel op het tandwielicoontje om de geavanceerde opties weer te geven. Daarna selecteer je vanaf welke stap de regel relevant is. De regel wordt uitgevoerd voor de aangegeven stap en alle stappen die erop volgen. Voorbeelden ----------- **Voorbeeld formulier** Onderstaande velden zijn opgenomen in de stap **Persoonlijk**: ======================== ============== Veld Waarde ======================== ============== Geslacht (keuzelijst) ``m`` Geboortedatum (datum) ``01-01-1979`` Uw inkomen (getal) ``30000`` Partner inkomen (getal) ``40000`` Woonplaats (tekst) ``Groningen`` ======================== ============== **Voorbeeld 1** U bent ouder dan 18 jaar: Waar **Als** [*Persoonlijk: Geboortedatum*] [*is groter dan*] [*vandaag*] [*minus*] ``18`` *jaren* **dan** ... **Voorbeeld 2** Uw inkomen is lager dan EUR 35.000: Waar **Als** [*Persoonlijk: Uw inkomen*] [*is kleiner dan*] [*waarde*] ``35000`` **Voorbeeld 3** Uw inkomen is lager dan dat van uw partner: Waar **Als** [*Persoonlijk: Uw inkomen*] [*is kleiner dan*] [*het veld*] [*Persoonlijk: Partner inkomen*] **dan** ... **Voorbeeld 4** U woont in Amsterdam, Haarlem of Utrecht: Onwaar **Als** [*Persoonlijk: Woonplaats*] [*in*] [*de lijst*] ``Amsterdam``, ``Haarlem``, ``Utrecht`` **dan** ... Acties ====== Nadat een regel is gedefinieerd, kunnen een of meerdere acties worden toegevoegd. De acties kunnen het formulier wijzigen afhankelijk van de gegevens die de gebruiker invult. Er zijn verschillende acties mogelijk: * **blokkeer doorgaan naar de volgende stap** - Doorgaan kan niet meer in het formulier. De knop om naar de volgende stap te gaan is verdwenen. * **wijzig een attribuut van een veld/component** - Met deze actie kan: * **verplicht** (ja/nee) - Een niet-verplicht veld wordt veranderd in een verplicht veld (of een verplicht veld wordt optioneel). * **verborgen** (ja/nee) - Een zichtbaar veld wordt verborgen (of een verborgen veld wordt zichtbaar) * **uitgeschakeld** (ja/nee) - Een veld blijft zichtbaar maar kan niet meer worden gewijzigd. * **wijzig de waarde van een variabele** - Met deze actie kan de waarde van een ** of andere ** worden veranderd naar de waarde van een ander veld of een waarde gekozen door de beheerder. * ** - Het veld dat gewijzigd moet worden. * ** - De waarde die op het te wijzigen ** word ingevuld. * **de waarde** - Een handmatig opgegeven waarde. * **het veld** - De waarde van een specifiek veld. * **markeer een stap als niet van toepassing.** - * ** - De formulierstap die als n.v.t. wordt aangemerkt. * **DMN evalueren** - Met deze actie kunnen beslistabellen uitgevoerd worden. Zie :ref:`manual_logic_dmn` voor meer details. Geavanceerde logica =================== De regels die we in de beheerinterface kunnen opstellen zijn beperkt qua complexiteit. Onder de motorkap wordt echter gebruik gemaakt van `JSON-logic`_ dat erg krachtig is en meer operaties en complexiteit toestaat dan mogelijk is met reguliere logica in Open Formulieren. Acties blijven hetzelfde. Met de link **Toon/verberg DSL weergave** bij reguliere logica wordt de JSON-logic achter de regels (en acties) getoond. We herhalen het voorbeeld dat eerder werd getoond: **Als** [*Gegevens: Geslacht*] [*is gelijk aan*] [*de waarde*] ``m`` **dan** [*wijzig de waarde van een veld*] [*Gegevens: Aanhef*] [*de waarde*] ``de heer`` De bijbehorende JSON-logic voor de regel (van **Als** tot **dan**) ziet er zo uit: .. code:: json { "==": [ { "var": "geslacht" }, "m" ] } Als we bovenstaande zouden plakken als regel bij geavanceerde logica, dan geeft dat hetzelfde resultaat als de (gebruiksvriendelijkere) regel bij reguliere logica. Hieronder volgen een aantal voorbeelden, die niet mogelijk zijn met reguliere logica. .. note:: Het is belangrijk dat het resultaat van een regel altijd **waar** (``true``) of **onwaar** (``false``) teruggeeft. De regel bepaald immers of de actie uitgevoerd moet worden of niet. Voorbeelden ----------- Stel, we hebben een formulier met daarin enkele velden. Hieronder staan de velden met hun **eigenschapsnaam** en de **waarde** die is ingevuld door de gebruiker. De inzendingsgegevens staan ook uitgedruk in *JSON* (het formaat waar de JSON-logic op werkt). .. note:: U kunt op de `JSON-logic`_ website naar **Play with it** gaan om de voorbeelden zelf te proberen: 1. Kopiëer de JSON code uit het JSON-tabblad hieronder, naar de website in het tekstvak onder **Data**. 2. Kopiëer de JSON code van een van de voorbeeld regels, naar de website in in het tekstvak onder **Rule** 3. Klik op **Compute** en er verschijnt of de regel waar of onwaar is. .. image:: _assets/jsonlogic.png :width: 100% .. note:: Open Forms gebruikt in de backend een `Python versie van JSON Logic`_. Een aantal JSON Logic operators zijn nog niet ondersteund: * filter * all * none * some * substr .. _Python versie van JSON Logic: https://github.com/maykinmedia/json-logic-py Voorbeeld formulier ^^^^^^^^^^^^^^^^^^^ .. tabs:: .. tab:: Formulier ======================== ============================ ============== Veld Eigenschapnaam / Variabele Waarde ======================== ============================ ============== Geslacht (keuzelijst) ``geslacht`` ``m`` Leeftijd (getal) ``leeftijd`` ``18`` Uw inkomen (getal) ``uwInkomen`` ``30000`` Partner inkomen (getal) ``partnerInkomen`` ``40000`` ======================== ============================ ============== .. tab:: JSON .. code:: json { "geslacht": "m", "leeftijd": 18, "uwInkomen": 30000, "partnerInkomen": 40000 } **Voorbeeld 1a** Geslacht (``geslacht``) is mannelijk (``m``): Waar (``true``). .. code:: json { "==": [{ "var": "geslacht" }, "m"] } **Voorbeeld 1b** Geslacht (``geslacht``) is vrouwelijk (``v``): Onwaar (``false``). .. code:: json { "==": [{ "var": "geslacht" }, "v"] } **Voorbeeld 2** Geslacht (``geslacht``) is mannelijk (``m``) en leeftijd (``leeftijd``) is groter of gelijk aan 18 (``18``): Waar (``true``). .. code:: json { "and" : [ { "==": [{ "var": "geslacht" }, "m"] }, { ">=": [{ "var": "leeftijd" }, 18] } ] } **Voorbeeld 3** Uw inkomen of die van uw partner is hoger dan EUR 35.000: Waar .. code:: json { "or" : [ { ">=": [{ "var": "uwInkomen" }, 35000] }, { ">=": [{ "var": "partnerInkomen" }, 35000] } ] } **Voorbeeld 4** Het inkomen van u en uw partner is samen hoger dan EUR 60.000: Waar .. code:: json { ">=" : [ { "+": [ { "var": "uwInkomen" }, { "var": "partnerInkomen" } ]}, 60000 ] } **Voorbeeld 5** U bent mannelijk, 18 jaar of ouder, en het gemiddelde inkomen van u en uw partner is hoger dan of gelijk aan EUR 35.000: Waar .. code:: json { "and" : [ { "==": [{ "var": "geslacht" }, "m"]}, { ">=": [{ "var": "leeftijd" }, 18]}, { ">=" : [ {"/": [ {"+": [ { "var": "uwInkomen" }, { "var": "partnerInkomen" } ]}, 2 ]}, 35000 ] } ] } .. note:: Dit voorbeeld is ook opgenomen als :ref:`voorbeeld formulier ` welke u kunt downloaden. .. _`JSON-logic`: https://jsonlogic.com/ Voorbeeld met vergelijking van datum en tijd ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Het is mogelijk om de datum / tijd component te vergelijken met de huidige datum / tijd. Bijvoorbeeld, deze trigger checkt of de datum / tijd van een evenement meer dan 24u in de toekomst is: .. tabs:: .. tab:: "duration" operator .. code:: json { ">": [ {"var": "datumTijdEvenement"}, { "datetime": { "+": [ {"var": "now"}, {"duration": "PT24H"} ] } } ] } .. tab:: "rdelta" operator Deze operator is verouderd en het is beter om de "duration" operator te gebruiken. .. code:: json { ">": [ {"var": "datumTijdEvenement"}, { "+": [ {"var": "now"}, {"rdelta": [0, 0, 0, 24]} ] } ] } Met ``duration`` is het mogelijk om berekeningen met datums te doen. De ``duration`` operator moet een `ISO 8601 'Duration'`_ bevatten. In de trigger hierboven, wordt een periode van 24 uren toegevoegd aan de datum / tijd van nu (``{"var": "now"}``). ``duration`` mag ook met datums worden gebruikt. Bijvoorbeeld: .. code:: json { ">": [ {"var": "datumEvenement"}, { "+": [ {"var": "today"}, {"duration": "P1M"} ] } ] } In de trigger hierboven, wordt een periode van 1 maand toegevoegd aan de datum van vandaag (``{"var": "today"}``). Als vandaag ``"2023-02-01"`` is, dan is ``"2023-03-01"`` het resultaat van ``{"+": [{"var": "today"}, {"duration": "P1M"}]}``. .. _ISO 8601 'Duration': https://en.wikipedia.org/wiki/ISO_8601#Durations Voorbeeld met vergelijking van tijdsperiodes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Het is ook mogelijk om tijdsperiodes te vergelijken. Bijvoorbeeld, deze trigger checkt of de periode tussen ``geboorteDatum`` en ``evenementDatum`` meer dan 18 jaren is. .. code:: json { "<": [ { "-": [ {"var": "geboorteDatum"}, {"var": "evenementDatum"} ] }, "P18Y" ] }