• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 22365193096

24 Feb 2026 06:46PM UTC coverage: 63.428% (-0.01%) from 63.44%
22365193096

push

github

mseaton
TRUNK-6569 - Encounter Service should validate against invalid order … (#5838)

1 of 1 new or added line in 1 file covered. (100.0%)

8 existing lines in 6 files now uncovered.

23198 of 36574 relevant lines covered (63.43%)

0.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.9
/api/src/main/java/org/openmrs/PatientIdentifier.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs;
11

12
import java.io.Serializable;
13
import java.lang.reflect.InvocationTargetException;
14
import java.lang.reflect.Method;
15
import java.util.Comparator;
16

17
import org.codehaus.jackson.annotate.JsonIgnore;
18
import org.hibernate.envers.Audited;
19
import org.hibernate.search.engine.backend.types.Sortable;
20
import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate;
21
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.AssociationInverseSide;
22
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
23
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField;
24
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField;
25
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
26
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexedEmbedded;
27
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency;
28
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.KeywordField;
29
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectPath;
30
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue;
31
import org.openmrs.api.db.hibernate.search.SearchAnalysis;
32
import org.openmrs.util.OpenmrsUtil;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
35

36
/**
37
 * A <code>Patient</code> can have zero to n identifying PatientIdentifier(s). PatientIdentifiers
38
 * are anything from medical record numbers, to social security numbers, to driver's licenses. The
39
 * type of identifier is defined by the PatientIdentifierType. A PatientIdentifier also contains a
40
 * Location.
41
 *
42
 * @see org.openmrs.PatientIdentifierType
43
 */
44
@Indexed
45
@Audited
46
public class PatientIdentifier extends BaseChangeableOpenmrsData implements java.io.Serializable, Cloneable, Comparable<PatientIdentifier> {
47
        
48
        public static final long serialVersionUID = 1123121L;
49
        
50
        private static final Logger log = LoggerFactory.getLogger(PatientIdentifier.class);
1✔
51
        
52
        // Fields
53
        
54
        /**
55
         * @since 1.5
56
         */
57
        @DocumentId
58
        private Integer patientIdentifierId;
59

60
        @IndexedEmbedded(includeEmbeddedObjectId = true)
61
        @AssociationInverseSide(inversePath = @ObjectPath({
62
                @PropertyValue(propertyName = "identifiers")
63
        }))
64
        private Patient patient;
65
        
66
        @FullTextField(name = "identifierPhrase", analyzer = SearchAnalysis.PHRASE_ANALYZER)
67
        @FullTextField(name = "identifierExact", analyzer = SearchAnalysis.EXACT_ANALYZER)
68
        @FullTextField(name = "identifierStart", analyzer = SearchAnalysis.START_ANALYZER, searchAnalyzer = SearchAnalysis.EXACT_ANALYZER)
69
        @FullTextField(name = "identifierAnywhere", analyzer = SearchAnalysis.ANYWHERE_ANALYZER, searchAnalyzer = SearchAnalysis.EXACT_ANALYZER)
70
        @KeywordField(name = "identifierExact_sort", sortable = Sortable.YES)
71
        private String identifier;
72

73
        @IndexedEmbedded(includeEmbeddedObjectId = true)
74
        @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
75
        private PatientIdentifierType identifierType;
76
        
77
        private Location location;
78

79
        private PatientProgram patientProgram;
80

81
        @GenericField
1✔
82
        private Boolean preferred = false;
1✔
83
        
84
        /** default constructor */
85
        public PatientIdentifier() {
1✔
86
        }
1✔
87
        
88
        /**
89
         * Convenience constructor for creating a basic identifier
90
         *
91
         * @param identifier String identifier
92
         * @param type PatientIdentifierType
93
         * @param location Location of the identifier
94
         */
95
        public PatientIdentifier(String identifier, PatientIdentifierType type, Location location) {
1✔
96
                this.identifier = identifier;
1✔
97
                this.identifierType = type;
1✔
98
                this.location = location;
1✔
99
        }
1✔
100
        
101
        /**
102
         * Compares this PatientIdentifier object to the given otherIdentifier. This method differs from
103
         * {@link #equals(Object)} in that this method compares the inner fields of each identifier for
104
         * equality. Note: Null/empty fields on <code>otherIdentifier</code> /will not/ cause a false
105
         * value to be returned
106
         *
107
         * @param otherIdentifier PatientiIdentifier with which to compare
108
         * @return boolean true/false whether or not they are the same names
109
         */
110
        public boolean equalsContent(PatientIdentifier otherIdentifier) {
111
                boolean returnValue = true;
1✔
112
                
113
                // these are the methods to compare.
114
                String[] methods = { "getIdentifier", "getIdentifierType", "getLocation" };
1✔
115
                
116
                Class<? extends PatientIdentifier> identifierClass = this.getClass();
1✔
117
                
118
                // loop over all of the selected methods and compare this and other
119
                for (String methodName : methods) {
1✔
120
                        try {
121
                                Method method = identifierClass.getMethod(methodName);
1✔
122
                                
123
                                Object thisValue = method.invoke(this);
1✔
124
                                Object otherValue = method.invoke(otherIdentifier);
1✔
125
                                
126
                                if (otherValue != null) {
1✔
127
                                        returnValue &= otherValue.equals(thisValue);
1✔
128
                                }
129
                                
130
                        }
131
                        catch (NoSuchMethodException e) {
×
132
                                log.warn("No such method for comparison " + methodName, e);
×
133
                        }
134
                        catch (IllegalAccessException | InvocationTargetException e) {
×
135
                                log.error("Error while comparing identifiers", e);
×
136
                        }
1✔
137

138
                }
139
                
140
                return returnValue;
1✔
141
        }
142
        
143
        //property accessors
144
        
145
        /**
146
         * @return Returns the identifier.
147
         */
148
        public String getIdentifier() {
149
                return identifier;
1✔
150
        }
151
        
152
        /**
153
         * @param identifier The identifier to set.
154
         */
155
        public void setIdentifier(String identifier) {
156
                this.identifier = identifier;
1✔
157
        }
1✔
158
        
159
        /**
160
         * @return Returns the identifierType.
161
         */
162
        public PatientIdentifierType getIdentifierType() {
163
                return identifierType;
1✔
164
        }
165
        
166
        /**
167
         * @param identifierType The identifierType to set.
168
         */
169
        public void setIdentifierType(PatientIdentifierType identifierType) {
170
                this.identifierType = identifierType;
1✔
171
        }
1✔
172
        
173
        /**
174
         * @return Returns the location.
175
         */
176
        public Location getLocation() {
177
                return location;
1✔
178
        }
179
        
180
        /**
181
         * @param location The location to set.
182
         */
183
        public void setLocation(Location location) {
184
                this.location = location;
1✔
185
        }
1✔
186
        
187
        /**
188
         * @return Returns the patient.
189
         */
190
        public Patient getPatient() {
191
                return patient;
1✔
192
        }
193
        
194
        /**
195
         * @param patient The patient to set.
196
         */
197
        public void setPatient(Patient patient) {
198
                this.patient = patient;
1✔
199
        }
1✔
200
        
201
        @Override
202
        public String toString() {
203
                return this.identifier;
1✔
204
        }
205
        
206
        /**
207
         * @return Returns the preferred.
208
         */
209
        public Boolean getPreferred() {
210
                return preferred;
1✔
211
        }
212
        
213
        /**
214
         * @param preferred The preferred to set.
215
         */
216
        public void setPreferred(Boolean preferred) {
217
                this.preferred = preferred;
1✔
218
        }
1✔
219
        
220
        /**
221
         * @return the preferred status
222
         * 
223
         * @deprecated as of 2.0, use {@link #getPreferred()}
224
         */
225
        @Deprecated
226
        @JsonIgnore
227
        public Boolean isPreferred() {
UNCOV
228
                return getPreferred();
×
229
        }
230
        
231
        /**
232
         * @see java.lang.Comparable#compareTo(java.lang.Object)
233
         * @deprecated since 1.12. Use DefaultComparator instead.
234
         * Note: this comparator imposes orderings that are inconsistent with equals.
235
         */
236
        @Deprecated
237
        @Override
238
        @SuppressWarnings("squid:S1210")
239
        public int compareTo(PatientIdentifier other) {
240
                DefaultComparator piDefaultComparator = new DefaultComparator();
1✔
241
                return piDefaultComparator.compare(this, other);
1✔
242
        }
243
        
244
        /**
245
         * @since 1.5
246
         * @see org.openmrs.OpenmrsObject#getId()
247
         */
248
        @Override
249
        public Integer getId() {
250
                return getPatientIdentifierId();
1✔
251
        }
252
        
253
        /**
254
         * @since 1.5
255
         * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
256
         */
257
        @Override
258
        public void setId(Integer id) {
259
                setPatientIdentifierId(id);
×
260
        }
×
261
        
262
        /**
263
         * @since 1.5
264
         * @return the patientIdentifierId
265
         */
266
        public Integer getPatientIdentifierId() {
267
                return patientIdentifierId;
1✔
268
        }
269
        
270
        /**
271
         * @since 1.5
272
         * @param patientIdentifierId the patientIdentifierId to set
273
         */
274
        public void setPatientIdentifierId(Integer patientIdentifierId) {
275
                this.patientIdentifierId = patientIdentifierId;
1✔
276
        }
1✔
277

278
        /**
279
         * bitwise copy of the PatientIdentifier object. NOTICE: THIS WILL NOT COPY THE PATIENT OBJECT. The
280
         * PatientIdentifier.patient object in this object AND the cloned object will point at the same
281
         * patient
282
         *
283
         * @return New PatientIdentifier object
284
         * @since 2.2.0
285
         */
286
        @Override
287
        public Object clone() {
288
                try {
289
                        return super.clone();
1✔
290
                }
291
                catch (CloneNotSupportedException e) {
×
292
                        throw new InternalError("PatientIdentifier should be cloneable");
×
293
                }
294
        }
295
        
296
        /**
297
         Provides a default comparator.
298
         @since 1.12
299
         **/
300
        public static class DefaultComparator implements Comparator<PatientIdentifier>, Serializable {
1✔
301

302
                private static final long serialVersionUID = 1L;
303
                
304
                @Override
305
                public int compare(PatientIdentifier pi1, PatientIdentifier pi2) {
306
                        int retValue = 0;
1✔
307
                        if (pi2 != null) {
1✔
308
                                retValue = pi1.getVoided().compareTo(pi2.getVoided());
1✔
309
                                if (retValue == 0) {
1✔
310
                                        retValue = pi1.getPreferred().compareTo(pi2.getPreferred());
1✔
311
                                }
312
                                if (retValue == 0) {
1✔
313
                                        retValue = OpenmrsUtil.compareWithNullAsLatest(pi1.getDateCreated(), pi2.getDateCreated());
1✔
314
                                }
315
                                if (pi1.getIdentifierType() == null && pi2.getIdentifierType() == null) {
1✔
316
                                        return 0;
1✔
317
                                }
318
                                if (pi1.getIdentifierType() == null && pi2.getIdentifierType() != null) {
1✔
319
                                        retValue = 1;
×
320
                                }
321
                                if (pi1.getIdentifierType() == null && pi2.getIdentifierType() != null) {
1✔
322
                                        retValue = -1;
×
323
                                }
324
                                if (retValue == 0) {
1✔
325
                                        retValue = OpenmrsUtil.compareWithNullAsGreatest(pi1.getIdentifierType().getPatientIdentifierTypeId(),
1✔
326
                                            pi2.getIdentifierType().getPatientIdentifierTypeId());
1✔
327
                                }
328
                                if (retValue == 0) {
1✔
329
                                        retValue = OpenmrsUtil.compareWithNullAsGreatest(pi1.getIdentifier(), pi2.getIdentifier());
1✔
330
                                }
331
                                
332
                                // if we've gotten this far, just check all identifier values.  If they are
333
                                // equal, leave the objects at 0.  If not, arbitrarily pick retValue=1
334
                                // and return that (they are not equal).
335
                                if (retValue == 0 && !pi1.equalsContent(pi2)) {
1✔
336
                                        retValue = 1;
1✔
337
                                }
338
                        }
339
                        
340
                        return retValue;
1✔
341
                }
342
        }
343

344

345
        /**
346
         * Gets patient program associated to the identifier in context
347
         * @since 2.6.0
348
         * @return patientProgram the patient program associated to an identifier
349
         */
350
        public PatientProgram getPatientProgram() {
351
                return patientProgram;
1✔
352
        }
353

354
        /**
355
         * This method sets the patient program on a patient Identifier
356
         * @since 2.6.0
357
         * @param patientProgram The patientProgram to set.
358
         */
359
        public void setPatientProgram(PatientProgram patientProgram) {
360
                this.patientProgram = patientProgram;
1✔
361
        }
1✔
362
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc