Commits

thomas@kvalitetsit.dk authored 64b2af51ab5


git-svn-id: https://svn.nspop.dk/svn/components/labsvar/trunk@1809 3203d48c-b89f-428c-a2b9-71f4dc330d7c
No tags

xdswrappers/documentprovider-parent/documentprovider/src/main/java/dk/nsi/dds/projects/sxa/documentprovider/document/PatientId.java

Added
1 +/**
2 + * The MIT License
3 + *
4 + * Original work sponsored and donated by National Board of e-Health (NSI), Denmark
5 + * (http://www.nsi.dk)
6 + *
7 + * Copyright (C) 2016 National Board of e-Health (NSI), Denmark (http://www.nsi.dk)
8 + *
9 + * Permission is hereby granted, free of charge, to any person obtaining a copy of
10 + * this software and associated documentation files (the "Software"), to deal in
11 + * the Software without restriction, including without limitation the rights to
12 + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
13 + * of the Software, and to permit persons to whom the Software is furnished to do
14 + * so, subject to the following conditions:
15 + *
16 + * The above copyright notice and this permission notice shall be included in all
17 + * copies or substantial portions of the Software.
18 + *
19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 + * SOFTWARE.
26 + */
27 +package dk.nsi.dds.projects.sxa.documentprovider.document;
28 +
29 +import java.util.regex.Pattern;
30 +
31 +import org.joda.time.DateTime;
32 +import org.joda.time.DateTimeZone;
33 +
34 +import dk.nsi.dds.projects.sxa.common.InvalidDateException;
35 +import dk.nsi.dds.projects.sxa.common.PatientIdDerivationException;
36 +
37 +/**
38 + * Holds an instance of a patient id (CPR and eCPR).
39 + */
40 +public class PatientId {
41 + private static final String DEFAULT_BIRTHDAY_FORMAT = "ddMMYYYY";
42 + private static final Pattern PATIENT_ID_PATTERN = Pattern.compile("^(\\d){10}$");
43 + public static final int NORMAL_DAY_RANGE_START = 1;
44 + public static final int NORMAL_DAY_RANGE_END = 31;
45 + public static final int ALTERNATIVE_DAY_RANGE_START = 61;
46 + public static final int ALTERNATIVE_DAY_RANGE_END = 91;
47 + public static final int YEAR_RANGE_START = 0;
48 + public static final int YEAR_RANGE_END = 99;
49 + public static final int MONTH_RANGE_START = 1;
50 + public static final int MONTH_RANGE_END = 12;
51 + public static final char GENDER_FEMALE = 'F';
52 + public static final char GENDER_MALE = 'M';
53 + private int day;
54 + private int month;
55 + private int year;
56 + private int controlCiffer;
57 + private boolean isAlternative;
58 + private String rawId;
59 +
60 + private PatientId(int day, int month, int year, int controlCiffer, boolean isAlternative, String rawId) {
61 + super();
62 + this.day = day;
63 + this.month = month;
64 + this.year = year;
65 + this.controlCiffer = controlCiffer;
66 + this.isAlternative = isAlternative;
67 + this.rawId = rawId;
68 + }
69 +
70 + public static PatientId createPatientId(String rawPatientId) throws PatientIdDerivationException {
71 + if (rawPatientId == null) {
72 + throw new PatientIdDerivationException("PatientId is null");
73 + }
74 + rawPatientId = rawPatientId.trim();
75 + if (!PATIENT_ID_PATTERN.matcher(rawPatientId).matches()) {
76 + throw new PatientIdDerivationException("PatientId format is invalid");
77 + }
78 + boolean isAlternative = isAlternative(rawPatientId);
79 + assertValidPatientDate(rawPatientId, isAlternative);
80 + return new PatientId(parseSubstring(rawPatientId, 0, 2), parseSubstring(rawPatientId, 2, 4),
81 + parseSubstring(rawPatientId, 4, 6), parseSubstring(rawPatientId, 6, 10), isAlternative, rawPatientId);
82 + }
83 +
84 + private static int parseSubstring(String text, int start, int end) {
85 + return Integer.parseInt(text.substring(start, end));
86 + }
87 +
88 + private static boolean isAlternative(String rawPatientId) throws PatientIdDerivationException {
89 + int day = Integer.parseInt(rawPatientId.substring(0, 2));
90 + if (day < NORMAL_DAY_RANGE_START || (day > NORMAL_DAY_RANGE_END && day < ALTERNATIVE_DAY_RANGE_START)
91 + || day > ALTERNATIVE_DAY_RANGE_END) {
92 + throw new PatientIdDerivationException("Day is invalid: " + day);
93 + }
94 + return day > NORMAL_DAY_RANGE_END;
95 + }
96 +
97 + /**
98 + * Verifies that given patient id has CPR number form and contains date information
99 + * which is sensible. The method must not be used as validation whether the patient
100 + * id identifies a real person or not.
101 + *
102 + * @param patientId
103 + * @throws PatientIdDerivationException
104 + */
105 + private static void assertValidPatientDate(String patientId, boolean isAlternative)
106 + throws PatientIdDerivationException {
107 + int day = Integer.parseInt(patientId.substring(0, 2));
108 + int month = Integer.parseInt(patientId.substring(2, 4));
109 + Integer.parseInt(patientId.substring(4, 6)); // year sensible?
110 + if (isAlternative) {
111 + day = day - ALTERNATIVE_DAY_RANGE_START + 1;
112 + }
113 + if (day < NORMAL_DAY_RANGE_START || day > NORMAL_DAY_RANGE_END || month < MONTH_RANGE_START
114 + || month > MONTH_RANGE_END) {
115 + throw new PatientIdDerivationException("Day and/or month not of sensible values in patient id");
116 + }
117 + }
118 +
119 + public char determineGender() throws PatientIdDerivationException {
120 + if (controlCiffer % 2 == 0) {
121 + return GENDER_FEMALE;
122 + }
123 + return GENDER_MALE;
124 + }
125 +
126 + /**
127 + * Calculates person birthday from person id. Algorithm for determining birth year
128 + * takes two first digits from current year, adds two digits from person id, and
129 + * compares the resulting year with current year. If resulting year is greater than
130 + * current year, 100 years are subtracted from the resulting year.
131 + *
132 + * Example: CurrentYear: 2015 PersonId: 010116 Output: 1916
133 + *
134 + * CurrentYear: 2015 personId: 010115 Output: 2015
135 + *
136 + * @param patientId
137 + * @return
138 + * @throws InvalidDateException
139 + */
140 + public DateTime deriveDateOfBirth() throws InvalidDateException {
141 + try {
142 + DateTime now = new DateTime(DateTimeZone.UTC);
143 + int currentYear = now.getYear();
144 + String currentYearText = currentYear + "";
145 + int proposedYear = Integer
146 + .parseInt(currentYearText.substring(0, currentYearText.length() - 2) + String.format("%02d", year));
147 + int correctedDay = isAlternative ? day - ALTERNATIVE_DAY_RANGE_START + 1 : day;
148 + DateTime result = new DateTime(proposedYear, month, correctedDay, 0, 0, DateTimeZone.UTC);
149 + if (result.isAfter(now)) {
150 + result = result.minusYears(100);
151 + }
152 + return result;
153 + } catch (Exception ex) {
154 + throw new InvalidDateException(ex);
155 + }
156 + }
157 +
158 + public String determineDateofBirthText() throws InvalidDateException {
159 + return determineDateofBirthText(DEFAULT_BIRTHDAY_FORMAT);
160 + }
161 +
162 + public String determineDateofBirthText(String format) throws InvalidDateException {
163 + return deriveDateOfBirth().toString(format);
164 + }
165 +
166 + public boolean isAlternative() {
167 + return isAlternative;
168 + }
169 +
170 + public String getRawId() {
171 + return rawId;
172 + }
173 +
174 + /**
175 + * Converts year to a two digit string e.g: 1980 -> 80
176 + *
177 + * @param year Complete year as a number
178 + * @return Truncated year as String
179 + */
180 + private static String yearToCprText(int year) {
181 + String textYear = Integer.toString(year);
182 + if (textYear.length() > 2) {
183 + return textYear.substring(textYear.length() - 2, textYear.length());
184 + }
185 + return textYear;
186 + }
187 +}

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut