diff --git a/README.md b/README.md index 3665a33..987a24f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Maven Site: [http://bekkopen.github.com/NoCommons/](http://bekkopen.github.com/N * validering * Bank * Kontonummer validering og generering + * KID generering * KID validering * Norsk språk o.l. * Konvertering av norske bokstaver i en tekst til de engelske erstatningene aa, ae og oe @@ -28,11 +29,8 @@ Maven Site: [http://bekkopen.github.com/NoCommons/](http://bekkopen.github.com/N * Sjekk om dato er arbeidsdag (dvs. ikke helligdag eller helg) * Legg til x antall arbeidsdager til en gitt dato * Liste ut alle helligdager - ## Features som ikke er implementert, men som kan passe inn -* Bank - * KID generator * Fylkesnummer * Finn fylkesnummer for fylke * Finn fylke for fylkesnummer diff --git a/pom.xml b/pom.xml index aab60c3..2f2ba0b 100644 --- a/pom.xml +++ b/pom.xml @@ -372,6 +372,6 @@ 2.4 UTF-8 - 1.5 + 1.6 diff --git a/src/main/java/no/bekk/bekkopen/banking/Kidnummer.java b/src/main/java/no/bekk/bekkopen/banking/Kidnummer.java index 90c3625..69aff4d 100644 --- a/src/main/java/no/bekk/bekkopen/banking/Kidnummer.java +++ b/src/main/java/no/bekk/bekkopen/banking/Kidnummer.java @@ -2,15 +2,66 @@ import no.bekk.bekkopen.common.StringNumber; +import java.math.BigInteger; + +import static no.bekk.bekkopen.common.Checksums.*; + /** * This class represent a Norwegian KID-nummer - a number used to identify * a customer on invoices. A Kidnummer consists of digits only, and the last * digit is a checksum digit (either mod10 or mod11). */ public class Kidnummer extends StringNumber { - - Kidnummer(String kontonummer) { - super(kontonummer); + + Kidnummer(String kidnummer) { + super(kidnummer); + } + + /** + * Return a valid mod10 Kidnummer by adding checksum digit + * @param baseNumber input number, digits only + * @return Kidnummer + */ + public static Kidnummer mod10Kid(String baseNumber) { + return Kidnummer.mod10Kid(baseNumber, baseNumber.length()+1); + } + + /** + * Create a valid KID numer of the wanted length, using MOD10. + * Input is padded with leading zeros to reach wanted target length + * @param baseNumber base number to calculate checksum digit for + * @param targetLength wanted length, 0-padded. Between 2-25 + * @return Kidnummer + */ + public static Kidnummer mod10Kid(String baseNumber, int targetLength) { + if (baseNumber.length() >= targetLength) + throw new IllegalArgumentException("baseNumber too long"); + String padded = String.format("%0" + (targetLength-1) + "d", new BigInteger(baseNumber)); + Kidnummer k = new Kidnummer(padded + "0"); + return KidnummerValidator.getKidnummer(padded + calculateMod10CheckSum(getMod10Weights(k), k)); + } + + /** + * Return a valid mod10 Kidnummer by adding checksum digit + * @param baseNumber input number, digits only + * @return Kidnummer + */ + public static Kidnummer mod11Kid(String baseNumber) { + return Kidnummer.mod11Kid(baseNumber, baseNumber.length()+1); } + /** + * Create a valid KID numer of the wanted length, using MOD11. + * Input is padded with leading zeros to reach wanted target length + * @param baseNumber base number to calculate checksum digit for + * @param targetLength wanted length, 0-padded. Between 2-25 + * @return Kidnummer + */ + public static Kidnummer mod11Kid(String baseNumber, int targetLength) { + if (baseNumber.length() >= targetLength) + throw new IllegalArgumentException("baseNumber too long"); + String padded = String.format("%0" + (targetLength-1) + "d", new BigInteger(baseNumber)); + Kidnummer k = new Kidnummer(padded + "0"); + return KidnummerValidator.getKidnummer(padded + calculateMod11CheckSum(getMod11Weights(k), k)); + } } diff --git a/src/main/java/no/bekk/bekkopen/banking/KidnummerValidator.java b/src/main/java/no/bekk/bekkopen/banking/KidnummerValidator.java index 97acafc..b80f937 100644 --- a/src/main/java/no/bekk/bekkopen/banking/KidnummerValidator.java +++ b/src/main/java/no/bekk/bekkopen/banking/KidnummerValidator.java @@ -6,6 +6,8 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import static no.bekk.bekkopen.common.Checksums.*; + public class KidnummerValidator extends StringNumberValidator implements ConstraintValidator { public static final String ERROR_LENGTH = "A Kidnummer is between 2 and 25 digits"; diff --git a/src/main/java/no/bekk/bekkopen/banking/KontonummerValidator.java b/src/main/java/no/bekk/bekkopen/banking/KontonummerValidator.java index 066a0ed..41f91e8 100644 --- a/src/main/java/no/bekk/bekkopen/banking/KontonummerValidator.java +++ b/src/main/java/no/bekk/bekkopen/banking/KontonummerValidator.java @@ -5,6 +5,10 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; +import static no.bekk.bekkopen.common.Checksums.calculateMod11CheckSum; +import static no.bekk.bekkopen.common.Checksums.getMod11Weights; + /** * Provides methods that validates if a Kontonummer is valid with respect to * syntax (length and digits only) and that the checksum digit is correct. diff --git a/src/main/java/no/bekk/bekkopen/common/Checksums.java b/src/main/java/no/bekk/bekkopen/common/Checksums.java new file mode 100644 index 0000000..f4b1429 --- /dev/null +++ b/src/main/java/no/bekk/bekkopen/common/Checksums.java @@ -0,0 +1,68 @@ +package no.bekk.bekkopen.common; + +public class Checksums { + public static final String ERROR_INVALID_CHECKSUM = "Invalid checksum : "; + private static int[] BASE_MOD11_WEIGHTS = new int[]{2, 3, 4, 5, 6, 7}; + + /** + * Calculate the check sum for the given weights and number. + * + * @param weights The weights + * @param number The number + * @return The checksum + */ + public static int calculateMod11CheckSum(int[] weights, StringNumber number) { + int c = calculateChecksum(weights, number, false) % 11; + if (c == 1) { + throw new IllegalArgumentException(ERROR_INVALID_CHECKSUM + number); + } + return c == 0 ? 0 : 11 - c; + } + + /** + * Calculate the check sum for the given weights and number. + * + * @param weights The weights + * @param number The number + * @return The checksum + */ + public static int calculateMod10CheckSum(int[] weights, StringNumber number) { + int c = calculateChecksum(weights, number, true) % 10; + return c == 0 ? 0 : 10 - c; + } + + public static int calculateChecksum(int[] weights, StringNumber number, boolean tverrsum) { + int checkSum = 0; + for (int i = 0; i < weights.length; i++) { + int product = weights[i] * number.getAt(weights.length - 1 - i); + if (tverrsum) { + checkSum += (product > 9 ? product - 9 : product); + } else { + checkSum += product; + } + } + return checkSum; + } + + public static int[] getMod10Weights(StringNumber k) { + int[] weights = new int[k.getLength() - 1]; + for (int i = 0; i < weights.length; i++) { + if ((i % 2) == 0) { + weights[i] = 2; + } else { + weights[i] = 1; + } + } + return weights; + } + + public static int[] getMod11Weights(StringNumber k) { + int[] weights = new int[k.getLength() - 1]; + for (int i = 0; i < weights.length; i++) { + int j = i % BASE_MOD11_WEIGHTS.length; + weights[i] = BASE_MOD11_WEIGHTS[j]; + } + return weights; + } + +} diff --git a/src/main/java/no/bekk/bekkopen/common/StringNumberValidator.java b/src/main/java/no/bekk/bekkopen/common/StringNumberValidator.java index 4bf58e7..865517f 100644 --- a/src/main/java/no/bekk/bekkopen/common/StringNumberValidator.java +++ b/src/main/java/no/bekk/bekkopen/common/StringNumberValidator.java @@ -6,56 +6,12 @@ */ public abstract class StringNumberValidator { - public static final String ERROR_INVALID_CHECKSUM = "Invalid checksum : "; - public static final String ERROR_SYNTAX = "Only digits are allowed : "; - - private static int[] BASE_MOD11_WEIGHTS = new int[]{2, 3, 4, 5, 6, 7}; - + protected StringNumberValidator() { super(); } - /** - * Calculate the check sum for the given weights and number. - * - * @param weights The weights - * @param number The number - * @return The checksum - */ - protected static int calculateMod11CheckSum(int[] weights, StringNumber number) { - int c = calculateChecksum(weights, number, false) % 11; - if (c == 1) { - throw new IllegalArgumentException(ERROR_INVALID_CHECKSUM + number); - } - return c == 0 ? 0 : 11 - c; - } - - /** - * Calculate the check sum for the given weights and number. - * - * @param weights The weights - * @param number The number - * @return The checksum - */ - protected static int calculateMod10CheckSum(int[] weights, StringNumber number) { - int c = calculateChecksum(weights, number, true) % 10; - return c == 0 ? 0 : 10 - c; - } - - private static int calculateChecksum(int[] weights, StringNumber number, boolean tverrsum) { - int checkSum = 0; - for (int i = 0; i < weights.length; i++) { - int product = weights[i] * number.getAt(weights.length - 1 - i); - if (tverrsum) { - checkSum += (product > 9 ? product - 9 : product); - } else { - checkSum += product; - } - } - return checkSum; - } - protected static void validateLengthAndAllDigits(String numberString, int length) { if (numberString == null || numberString.length() != length) { @@ -74,26 +30,4 @@ protected static void validateAllDigits(String numberString) { } } } - - protected static int[] getMod10Weights(StringNumber k) { - int[] weights = new int[k.getLength() - 1]; - for (int i = 0; i < weights.length; i++) { - if ((i % 2) == 0) { - weights[i] = 2; - } else { - weights[i] = 1; - } - } - return weights; - } - - protected static int[] getMod11Weights(StringNumber k) { - int[] weights = new int[k.getLength() - 1]; - for (int i = 0; i < weights.length; i++) { - int j = i % BASE_MOD11_WEIGHTS.length; - weights[i] = BASE_MOD11_WEIGHTS[j]; - } - return weights; - } - } diff --git a/src/main/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidator.java b/src/main/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidator.java index 9ece14a..0a9f863 100644 --- a/src/main/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidator.java +++ b/src/main/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidator.java @@ -5,6 +5,10 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; +import static no.bekk.bekkopen.common.Checksums.calculateMod11CheckSum; +import static no.bekk.bekkopen.common.Checksums.getMod11Weights; + /** * Provides methods that validates if an Organisasjonsnummer is valid with * respect to syntax (length and digits only) and that the checksum digit is diff --git a/src/main/java/no/bekk/bekkopen/person/FodselsnummerValidator.java b/src/main/java/no/bekk/bekkopen/person/FodselsnummerValidator.java index baee994..4b60e5a 100644 --- a/src/main/java/no/bekk/bekkopen/person/FodselsnummerValidator.java +++ b/src/main/java/no/bekk/bekkopen/person/FodselsnummerValidator.java @@ -8,6 +8,9 @@ import java.text.ParseException; import java.text.SimpleDateFormat; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; +import static no.bekk.bekkopen.common.Checksums.calculateMod11CheckSum; + /** * Provides methods that validates if a Fodselsnummer is valid with respect to * syntax, Individnummer, Date and checksum digits. diff --git a/src/test/java/no/bekk/bekkopen/banking/KidnummerTest.java b/src/test/java/no/bekk/bekkopen/banking/KidnummerTest.java new file mode 100644 index 0000000..2b1979a --- /dev/null +++ b/src/test/java/no/bekk/bekkopen/banking/KidnummerTest.java @@ -0,0 +1,54 @@ +package no.bekk.bekkopen.banking; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class KidnummerTest { + @Test + public void mod10Kid() throws Exception { + assertValidKid("0000001230", Kidnummer.mod10Kid("123", 10)); + assertValidKid("0000012344", Kidnummer.mod10Kid("1234", 10)); + } + + @Test + public void mod11Kid() throws Exception { + assertValidKid("0000001236", Kidnummer.mod11Kid("123", 10)); + assertValidKid("0000012343", Kidnummer.mod11Kid("1234", 10)); + } + + @Test(expected = IllegalArgumentException.class) + public void tooLongBaseMod10() { + Kidnummer.mod10Kid("1234567890", 3); + } + + @Test(expected = IllegalArgumentException.class) + public void tooLongBaseMod101() { + Kidnummer.mod11Kid("1234567890", 3); + } + + @Test(expected = IllegalArgumentException.class) + public void belowRangeMod10() { + Kidnummer.mod10Kid("12", 1); + } + + @Test(expected = IllegalArgumentException.class) + public void belowRangeMod11() { + Kidnummer.mod11Kid("12", 1); + } + + @Test(expected = IllegalArgumentException.class) + public void aboveRangeMod10() { + Kidnummer.mod10Kid("12", 26); + } + + @Test(expected = IllegalArgumentException.class) + public void aboveRangeMod11() { + Kidnummer.mod11Kid("12", 26); + } + + private void assertValidKid(String expected, Kidnummer kidnummer) { + KidnummerValidator.isValid(kidnummer.toString()); + assertEquals(expected, kidnummer.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/no/bekk/bekkopen/banking/KidnummerValidatorTest.java b/src/test/java/no/bekk/bekkopen/banking/KidnummerValidatorTest.java index 1caad93..8c95d4b 100644 --- a/src/test/java/no/bekk/bekkopen/banking/KidnummerValidatorTest.java +++ b/src/test/java/no/bekk/bekkopen/banking/KidnummerValidatorTest.java @@ -5,6 +5,7 @@ import org.junit.Test; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; import static org.junit.Assert.*; public class KidnummerValidatorTest extends NoCommonsTestCase { @@ -61,7 +62,7 @@ public void testInvalidKidnummerWrongChecksum() { KidnummerValidator.validateChecksum(KIDNUMMER_INVALID_CHECKSUM); fail(); } catch (IllegalArgumentException e) { - assertMessageContains(e, StringNumberValidator.ERROR_INVALID_CHECKSUM); + assertMessageContains(e, ERROR_INVALID_CHECKSUM); } } diff --git a/src/test/java/no/bekk/bekkopen/banking/KontonummerValidatorTest.java b/src/test/java/no/bekk/bekkopen/banking/KontonummerValidatorTest.java index 5aef7e0..f42b42a 100644 --- a/src/test/java/no/bekk/bekkopen/banking/KontonummerValidatorTest.java +++ b/src/test/java/no/bekk/bekkopen/banking/KontonummerValidatorTest.java @@ -1,5 +1,6 @@ package no.bekk.bekkopen.banking; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -38,7 +39,7 @@ public void testInvalidKontonummerWrongChecksum() { KontonummerValidator.validateChecksum(KONTONUMMER_INVALID_CHECKSUM); fail(); } catch (IllegalArgumentException e) { - assertMessageContains(e, KontonummerValidator.ERROR_INVALID_CHECKSUM); + assertMessageContains(e, ERROR_INVALID_CHECKSUM); } } diff --git a/src/test/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidatorTest.java b/src/test/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidatorTest.java index 9bf53f3..5335035 100644 --- a/src/test/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidatorTest.java +++ b/src/test/java/no/bekk/bekkopen/org/OrganisasjonsnummerValidatorTest.java @@ -1,5 +1,6 @@ package no.bekk.bekkopen.org; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -38,7 +39,7 @@ public void testInvalidOrgnummerWrongChecksum() { OrganisasjonsnummerValidator.validateChecksum(ORGNUMMER_INVALID_CHECKSUM); fail(); } catch (IllegalArgumentException e) { - assertMessageContains(e, OrganisasjonsnummerValidator.ERROR_INVALID_CHECKSUM); + assertMessageContains(e, ERROR_INVALID_CHECKSUM); } } diff --git a/src/test/java/no/bekk/bekkopen/person/FodselsnummerValidatorTest.java b/src/test/java/no/bekk/bekkopen/person/FodselsnummerValidatorTest.java index 52f3556..7e5f40c 100644 --- a/src/test/java/no/bekk/bekkopen/person/FodselsnummerValidatorTest.java +++ b/src/test/java/no/bekk/bekkopen/person/FodselsnummerValidatorTest.java @@ -1,5 +1,6 @@ package no.bekk.bekkopen.person; +import static no.bekk.bekkopen.common.Checksums.ERROR_INVALID_CHECKSUM; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -95,7 +96,7 @@ public void testInvalidFodselsnummerChecksum() { FodselsnummerValidator.validateChecksums("01010101010"); fail(); } catch (IllegalArgumentException e) { - assertMessageContains(e, FodselsnummerValidator.ERROR_INVALID_CHECKSUM); + assertMessageContains(e, ERROR_INVALID_CHECKSUM); } }