Resultatberäkning på djupet

Denna sida beskriver hur beräkningar går till och hur de kan skrivas samt vad man bör tänka på. Löpande i dokumentet finns kodexempel där vi visar på olika sätt att skriva en beräkning. Vi har försökt att skriva så författare av resultatberäkning utan teknisk bakgrund skall förstå men ibland behöver tyvärr använda oss av tekniska termer då det krävs.

Gå direkt till rubriken:

Beräkningar i 1177 formulärhantering

På en formulärmall kan en eller flera beräkningar skapas som skall utföras baserat på ett besvarat formulär.

Beräkningen/beräkningarna utförs automatiskt när ett formulär besvaras.

En beräkning blir en kodsnutt som skall exekveras. Det är författarens ansvar att beräkningen görs på ett korrekt och effektivt sätt samt att man följer Formulärtjänstens regler.

Beräkningstyper

Vi har idag stöd för en typ av beräkningar och det är "inera:form-engine:drools-java:1". Om man använder Fristående personalgränssnittet används detta automatiskt. Om resultatberäkningsmotorn, vilket är den IT-komponent där beräkningen utförs, ser en beräkning av typen "inera:form-engine:drools-java:1" på mallen så kommer denna utföras.

Andra anslutna tjänster såsom Cosmic, EyeDoc, Provisio mfl. kanske redan har stöd för beräkningar och de kan då spara dessa på en mall som en egen typ och senare själva göra beräkningar på det besvarade formuläret. Det är då självklart viktigt att man anger en annan typ än den som resultatberäkningsmotorn känner till och som är unik för anropande system.

Drools och 1177 formulärhantering

Stödet för beräkningstypen 'inera:form-engine:drools-java:1' bygger på Drools (kie) som är en regelmotor byggd med programmeringsspråket Java. 

Vi erbjuder ett delmängd av funktionerna i Drools, t.ex kan man bara ha en regel (rule) som vi kallar beräkning och denna är något reducerad. Vi använder oss också av dialekten Java när en beräkning skrivs. Mer utförlig beskrivning om detta hittar du längre ner.

Hur går en beräkning till?

Struktur

En beräkning består av två block, when och then som avslutas med end. 

when   ... (LHS) then   ... (RHS) end

WHEN blocket innehåller ett eller flera villkor som skall vara uppfyllda för att beräkningen skall utföras. Denna delen kallas ofta LHS, left hand side.

THEN blocket innehåller de beräkningar som skall utföras då villkoret i WHEN blocket är uppfyllt. Denna delen kallas ofta RHS, right hand side

Exempel

when   $q: Questions()   eval($q.get("vikt") != null)   eval($q.get("längd") != null)   eval($q.get("längd") > 0) then     double bmi = $q.get("vikt") / ($q.get("längd")/100 * $q.get("längd")/100);     outcome.set(bmi); end

Fakta

Fakta är något som vi vill använda i vår beräkning. Fakta från formuläret är en lista med alla frågor och dess svar, namnet på denna lista är Questions.

Questions måste man själv göra tillgänglig som en egen variabel, i exemplet nedan kallar vi variabeln för $q.

Questions innehåller då nyckel/värde par där nyckel är Frågans id och värde är svaret på frågan.

Svaret på en fråga i faktan representeras av en Double i Java som är ett flyttal.

Det finns vissa villkor som måste vara uppfyllda för att en fråga skall vara med som fakta:

  • En fråga måste ha ett unikt id, Frågans id (questionId)

  • En fråga kan bara ha ett svar, flervalsfrågor stöds inte i nuläget

  • En fråga utan svar (null) tas inte med som fakta till beräkningen.

  • Frågor av typen tal och skala (number, range) ingår med dess svarsvärde.

  • Frågor av typen rullgardin och enval (radio, matrixradio och select) ingår och där svaret är svarsalternativets ordningstal (answerAlternativeNumber)

when   $q: Questions()  // här gör vi Questions tillgänglig med namnet $q   eval($q.get("vikt") != null)   eval($q.get("längd") != null)   eval($q.get("längd") > 0) then   ....... end

Beskrivning av objektet Questions

 

Retur

Metod

Beskrivning

java.lang.Double

get(java.lang.String questionId)

Returnera svarsvärde för fråga med id questionId

java.lang.Double

get(java.lang.String questionId, java.lang.Double defaultValue)

Returnera svarsvärde för fråga med id questionId. Om svarsvärde är null returneras defaultValue

java.lang.Double

get(java.lang.String questionId, java.lang.Integer defaultValue)

Returnera svarsvärde för fråga med id questionId. Om svarsvärde är null returneras defaultValue

 

Resultat

Resultatet för beräkningen, som vi själva skall sätta, finns alltid tillgängligt i then-blocket med namnet outcome

Outcome har ett värde (value) och är av Java typen Double som är ett flyttal.

Outcome har en metod för att sätta värdet och denna metoden har namnet set, Outcome.set(Double value).

Beskrivning av objektet Outcome

 

Retur

Metod

Beskrivning

void

set(java.lang.Double value)

Sätt värde för resultat

 

Kommentarer i beräkningen

Ibland kan det finnas behov av skriva kommentarer i sin beräkning. Det finns två typer av kommenterar, enrads-  och flerradkommentar.

Enradskommentar skrivs med två snedstreck // och flerradskommentar skrivs med symbolen /* för att starta kommentaren och  */ för att avsluta kommentaren

Variabler

Man kan skapa egna variabler som sedan kan användas i en formel. Man måste själv sätta vilken datatyp som avses för variabeln och det är Javas datatyper, primitiver och klasser,  som finns tillgängliga att användas.

Tänk på att syntaxen för variabelnamn skiljer på versaler och gemener vilket innebär att namnet vikt inte är samma som Vikt.

Se längre ner för beskrivning av Javas datatyper

 

Syntax och Java dialekt

För att skriva beräkningar så använder vi oss av Drools egna DSL samt Java syntax. Drools DSL (Domain Specific Language) är specific syntax och för att skriva Drools regler använder vi Drools Rule Language (DRL), dock är det bara en delmängd av DRL:en som används vid en resultatberäkning. Det är alltså Java syntax till stor del som styr hur en beräkning skrivs och i Java syntax så finns det en del regler som måste följas men det innebär också att vi får tillgång till Javas operatorer, flödeskontroller, primitiver och standard klasser. För att skriva enkla beräkningar så behöver man inte vara en fullfjädrad programmerare utan det räcker långt att man tittar på de kodexempel som finns för att göra sin beräkning. Om man sedan vill göra en mer avancerad beräkning så hjälper det självklart om man har grundläggande förståelse om programmering och då gärna specifikt för Java.

En viktig sak som är lätt att missa är att varje operation i when-blocket skall avslutas med semikolon (;) som är java syntax.

Vi har också tillgång till Drools egna operatorer som då används i when-blocket.

Java operatorer

En operator används när du vill utföra en operation på en variabel. Nedan följder några vanliga operatorer:

+ , - , * , /

addition,

subtraktion,

multiplikation,

division

== , !=

lika med, 

inte lika med

> , < , >= , <= 

större än,

mindre än,

större än eller lika med,

mindre än eller lika med

&& , ||

logiskt och (AND),

logiskt eller (OR)

=

tilldela en variabel ett värde

Läs mer om Java operatorer här: Operators

Nedan ser du exempel på hur olika operatorer kan användas.

 

Flödeskontroller

I then-blocket så vill man kanske styra flödet beroende på variabelvärden men använder då Javas flödeskontroller för att åstadkomma detta.

Flödeskontroller som finns tillgängliga i Java.

if-then, if-then-else, switch

används för villkor

for, while, do-while

används för iteration

break, continue, return

uthopp

Nedan ser du exempel på hur olika flödeskontroller kan användas.

Datatyper

När vi skriver en beräkning så har vi också tillgång till Javas primitiver och standard klasser.

Viktigt är att se och förstå skillnaden på en primitiv och och dess motsvarande klass. Till exempel har primitiven double en motsvarande klass med namnet Double.

  • En primitiv börjar alltid med en gemen och en klass börjar alltid med en versal.

  • En primitiv kan aldrig vara null.

Om man inte har behov av att använda null-värden så rekommenderas att använda primitiver, alltså de som börjar med en gemen.

För den som är intresserad så finns bra beskrivning om Javas primitiver och standard klasser.

Drools operatorer och nyckelord

Då Drools DRL har en egen syntax så finns flera operatorer och nyckelord som kan användas men dock inte alla. Det som syns mest av Drools för en författare av resultatberäkning är nyckelorden when , then och end samt det som kan användas i when-blocket.

Om du är intresserad av Drools och vill läsa mer så hittar det information på deras hemsida och i deras dokumentation.

Att tänka på

Att skriva resultatberäkning är till viss del programmering och man behöver veta och tänka på vissa saker för att det skall bli bra och av hög kvalité.

Kontrollera Null värden

Man skall alltid kontrollera att ett värde inte är null innan man försöker använda det för annars får man ett fel vid beräkningen. Att ett värde är null för en fråga kan bland annat bero på att frågan inte är satt som obligatorisk. Om det är ett fakta som man vet skall finnas så skall kontrollen göras i when-blocket eftersom ingen beräkning då kommer utföras. 

Nedan ser du en kontroll på att flera villkor måste vara uppfyllda och de binds ihop med och. Kontrollen nedan skall läsas enligt följande: vikt skall inte vara null och längd skall inte vara null. Vi ser även att vi lagt till att längd skall vara större än 0, eftersom vi inte vill dividera med 0

Om man vill använda ett icke obligatorsikt svar i then-blocket så med en if-sats. I det fiktiva exemplet nedan vill vi ge alla som är äldre än 55 år lite bonus (3) på sitt framräknade bmi värde. Koden nedan skall då läsas: om variabeln alder inte är null och variabeln alder är större än 55 då vill man utföra det som finns inom klammarparantes ({})

Vi skulle också kunna använde den inbyggda möjligheten som finns att returna ett standardvärde om det verkliga svarsvärdet är null.

Dividera inte med noll

Ett vanligt fel att är att man inte kontrollerar värdet innan det används. Om man till exempel försöker dividera med en variabel som har värdet noll (0) resulterar det i felet divide by zero.

I följande exempel kontrollerar vi svaret för fråga med id längd att det inte är null och är större än noll.