Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legg til wrappere for fnr og orgnr #20

Merged
merged 5 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/main/kotlin/no/nav/helsearbeidsgiver/utils/wrapper/Fnr.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package no.nav.helsearbeidsgiver.utils.wrapper

import kotlinx.serialization.Serializable

/** Sjekker at streng er riktig lengde, kun består av siffer, og at 6 første siffer er gyldig dato. */
private val fnrRgx = Regex(
"(?:[04][1-9]|[1256]\\d|[37][01])" + // to første siffer er gyldig dag (+40 for D-nummer)
"(?:[048][1-9]|[159][012])" + // to neste siffer er gyldig måned, med støtte for testpersoner (+40 for NAV, +80 for TestNorge)
"\\d{7}" // resten er tall
)

private val sifferVekter1 = listOf(3, 7, 6, 1, 8, 9, 4, 5, 2)
private val sifferVekter2 = listOf(5, 4, 3, 2, 7, 6, 5, 4, 3, 2)

@Serializable
@JvmInline
value class Fnr(val verdi: String) {
init {
require(erGyldig(verdi)) { "Ugyldig fødsels- eller d-nummer." }
}

override fun toString(): String =
verdi

companion object {
/** Les [her](https://no.wikipedia.org/wiki/F%C3%B8dselsnummer) for forklaring av regler. */
fun erGyldig(fnr: String): Boolean =
if (fnr.matches(fnrRgx)) {
val fnrSiffer = fnr.toList().map(Char::digitToInt)

val sjekksum1 = sjekksum(fnrSiffer, sifferVekter1)
val sjekksum2 = sjekksum(fnrSiffer, sifferVekter2)

10 !in listOf(sjekksum1, sjekksum2) &&
sjekksum1 == fnrSiffer[9] &&
sjekksum2 == fnrSiffer[10]
} else {
false
}
}
}
34 changes: 34 additions & 0 deletions src/main/kotlin/no/nav/helsearbeidsgiver/utils/wrapper/Orgnr.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package no.nav.helsearbeidsgiver.utils.wrapper

import kotlinx.serialization.Serializable

/** Sjekker at streng er riktig lengde og kun består av siffer. */
private val orgnrRgx = Regex("\\d{9}")

private val sifferVekter = listOf(3, 2, 7, 6, 5, 4, 3, 2)

@Serializable
@JvmInline
value class Orgnr(val verdi: String) {
init {
require(erGyldig(verdi)) { "Ugyldig organisasjonsnummer." }
}

override fun toString(): String =
verdi

companion object {
/** Les [her](https://www.brreg.no/om-oss/registrene-vare/om-enhetsregisteret/organisasjonsnummeret/) for forklaring av regler. */
fun erGyldig(orgnr: String): Boolean =
if (orgnr.matches(orgnrRgx)) {
val orgnrSiffer = orgnr.toList().map(Char::digitToInt)

val sjekksum = sjekksum(orgnrSiffer, sifferVekter)

sjekksum != 10 &&
sjekksum == orgnrSiffer.last()
} else {
false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package no.nav.helsearbeidsgiver.utils.wrapper

internal fun sjekksum(siffer: List<Int>, sifferVekter: List<Int>): Int =
siffer.zip(sifferVekter)
.sumOf { (siffer, vekt) -> siffer * vekt }
.mod(11)
.let { 11 - it }
.mod(11)
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package no.nav.helsearbeidsgiver.utils.wrapper

import io.kotest.assertions.throwables.shouldNotThrowAny
import io.kotest.assertions.throwables.shouldThrowExactly
import io.kotest.core.spec.style.FunSpec
import io.kotest.datatest.withData
import io.kotest.matchers.shouldBe

class FnrTest : FunSpec({

context("gyldig") {
withData(
listOf(
"01010012356",
"19092212338",
"29104512346",
"31129912319",
"25056812310",
"11085812345",
"41066712395", // D-nummer
"45066612310", // D-nummer
"50066612306", // D-nummer
"56066612320", // D-nummer
"60066612387", // D-nummer
"69066612309", // D-nummer
"70066712379", // D-nummer
"71066612397", // D-nummer
"01490012369", // Testperson fra NAV
"01500012397", // Testperson fra NAV
"01890012341", // Testperson fra TestNorge
"01900912338" // Testperson fra TestNorge
)
) {
shouldNotThrowAny {
Fnr(it)
}
}
}

context("ugyldig") {
withData(
listOf(
"00010012317", // dag 0, andre siffer feil
"32010012308", // dag 32, andre siffer feil
"40010012300", // dag 40, andre siffer feil (D-nummer)
"72010012482", // dag 72, andre siffer feil (D-nummer)
"80010012485", // dag 80, første siffer feil
"01000012366", // måned 0, fjerde siffer feil
"01130012384", // måned 13, fjerde siffer feil
"01200012352", // måned 20, tredje siffer feil
"01390012310", // måned 39, tredje og fjerde siffer feil
"01400012349", // måned 40, fjerde siffer feil (testperson)
"01530012367", // måned 53, fjerde siffer feil (testperson)
"01790012484", // måned 79, tredje og fjerde siffer feil
"01800012321", // måned 80, fjerde siffer feil (testperson)
"01930012420", // måned 93, fjerde siffer feil (testperson)
"0101001234", // for kort
"010100123567", // for langt
"010100x2345", // med bokstav
"010100 1234", // med mellomrom
"01010012313", // ugyldig kontrollsiffer 1
"19092212389", // ugyldig kontrollsiffer 1
"060606123-3", // ugyldig kontrollsiffer 1 (sjekksum = 10)
"060606123103", // ugyldig kontrollsiffer 1 (sjekksum = 10)
"41066712336", // ugyldig kontrollsiffer 1 (D-nummer)
"01490012326", // ugyldig kontrollsiffer 1 (Testperson fra NAV)
"01890012309", // ugyldig kontrollsiffer 1 (Testperson fra TestNorge)
"29104512344", // ugyldig kontrollsiffer 2
"31129912310", // ugyldig kontrollsiffer 2
"1403551234-", // ugyldig kontrollsiffer 2 (sjekksum = 10)
"140355123410", // ugyldig kontrollsiffer 2 (sjekksum = 10)
"45066612316", // ugyldig kontrollsiffer 2 (D-nummer)
"01500012390", // ugyldig kontrollsiffer 2 (Testperson fra NAV)
"01900912339" // ugyldig kontrollsiffer 2 (Testperson fra TestNorge)
)
) {
shouldThrowExactly<IllegalArgumentException> {
Fnr(it)
}
}

test("tom streng") {
shouldThrowExactly<IllegalArgumentException> {
Fnr("")
}
}
}

test("toString gir wrappet verdi") {
Fnr("24120612359").let {
it.toString() shouldBe it.verdi
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package no.nav.helsearbeidsgiver.utils.wrapper

import io.kotest.assertions.throwables.shouldNotThrowAny
import io.kotest.assertions.throwables.shouldThrowExactly
import io.kotest.core.spec.style.FunSpec
import io.kotest.datatest.withData
import io.kotest.matchers.shouldBe

class OrgnrTest : FunSpec({

context("gyldig") {
withData(
listOf(
"161231657",
"908498461",
"135103217",
"684603132",
"167484972",
"796033029"
)
) {
shouldNotThrowAny {
Orgnr(it)
}
}
}

context("ugyldig") {
withData(
listOf(
"1233", // for kort
"1234567895", // for langt
"12x4567890", // med bokstav
"1234 67892", // med mellomrom
"161231654", // ugyldig kontrollsiffer
"908498464", // ugyldig kontrollsiffer
"65432445-", // ugyldig kontrollsiffer (sjekksum = 10)
"6543244510" // ugyldig kontrollsiffer (sjekksum = 10)
)
) {
shouldThrowExactly<IllegalArgumentException> {
Orgnr(it)
}
}

test("tom streng") {
shouldThrowExactly<IllegalArgumentException> {
Orgnr("")
}
}
}

test("toString gir wrappet verdi") {
Orgnr("123456785").let {
it.toString() shouldBe it.verdi
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package no.nav.helsearbeidsgiver.utils.wrapper

import io.kotest.core.spec.style.FunSpec
import io.kotest.datatest.withData
import io.kotest.matchers.shouldBe

class SjekksumTest : FunSpec({
context("gyldig") {
withData(
mapOf(
"siffer og sifferVekter er tomme" to TestData(
siffer = emptyList(),
sifferVekter = emptyList(),
forventetSjekksum = 0
),
"siffer er tom" to TestData(
siffer = emptyList(),
sifferVekter = listOf(1, 2, 3),
forventetSjekksum = 0
),
"sifferVekter er tom" to TestData(
siffer = listOf(1, 2, 3),
sifferVekter = emptyList(),
forventetSjekksum = 0
),
"siffer er kortere enn sifferVekter" to TestData(
siffer = listOf(3),
sifferVekter = listOf(5, 7, 9),
forventetSjekksum = 7
),
"sifferVekter er kortere enn siffer" to TestData(
siffer = listOf(2, 4, 6),
sifferVekter = listOf(8),
forventetSjekksum = 6
),
"krever ikke enkeltsiffer" to TestData(
siffer = listOf(13),
sifferVekter = listOf(14),
forventetSjekksum = 5
),
"sjekksum kalkuleres korrekt (1 av 2)" to TestData(
siffer = listOf(4, 4, 9),
sifferVekter = listOf(9, 3, 4),
forventetSjekksum = 4
),
"sjekksum kalkuleres korrekt (2 av 2)" to TestData(
siffer = listOf(4, 8, 4, 8),
sifferVekter = listOf(3, 8, 2, 1),
forventetSjekksum = 7
),
"sjekksum er tosifret" to TestData(
siffer = listOf(3, 1, 0, 5, 3),
sifferVekter = listOf(6, 8, 4, 2, 3),
forventetSjekksum = 10
),
"sjekksum er 0" to TestData(
siffer = listOf(7, 5, 6, 5, 1, 2, 1),
sifferVekter = listOf(0, 6, 0, 9, 9, 2, 0),
forventetSjekksum = 0
)
)
) {
sjekksum(it.siffer, it.sifferVekter) shouldBe it.forventetSjekksum
}
}
})

private data class TestData(
val siffer: List<Int>,
val sifferVekter: List<Int>,
val forventetSjekksum: Int
)
Loading