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

openmrs / openmrs-core / 10946298164

19 Sep 2024 05:33PM UTC coverage: 63.759% (+0.09%) from 63.671%
10946298164

push

github

mogoodrich
TRUNK-6265: Bugs in Concept.getPreferredName(Locale) method (#4749)

(cherry picked from commit bc725f242)

14 of 16 new or added lines in 1 file covered. (87.5%)

12 existing lines in 9 files now uncovered.

21692 of 34022 relevant lines covered (63.76%)

0.64 hits per line

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

87.86
/api/src/main/java/org/openmrs/Person.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.text.ParseException;
13
import java.text.SimpleDateFormat;
14
import java.util.ArrayList;
15
import java.util.Calendar;
16
import java.util.Date;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.TreeSet;
22

23
import javax.persistence.Transient;
24
import org.codehaus.jackson.annotate.JsonIgnore;
25
import org.hibernate.search.annotations.Analyze;
26
import org.hibernate.search.annotations.ContainedIn;
27
import org.hibernate.search.annotations.DateBridge;
28
import org.hibernate.search.annotations.DocumentId;
29
import org.hibernate.search.annotations.EncodingType;
30
import org.hibernate.search.annotations.Field;
31
import org.hibernate.search.annotations.Resolution;
32
import org.openmrs.util.OpenmrsUtil;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
35
import org.springframework.util.StringUtils;
36

37
/**
38
 * A Person in the system. This can be either a small person stub, or indicative of an actual
39
 * Patient in the system. This class holds the generic person things that both the stubs and
40
 * patients share. Things like birthdate, names, addresses, and attributes are all generified into
41
 * the person table (and hence this super class)
42
 * 
43
 * @see org.openmrs.Patient
44
 */
45
public class Person extends BaseChangeableOpenmrsData {
46
        
47
        public static final long serialVersionUID = 2L;
48
        
49
        private static final Logger log = LoggerFactory.getLogger(Person.class);
1✔
50
        
51
        @DocumentId
52
        protected Integer personId;
53
        
54
        private Set<PersonAddress> addresses = null;
1✔
55
        
56
        @ContainedIn
1✔
57
        private Set<PersonName> names = null;
58
        
59
        @ContainedIn
1✔
60
        private Set<PersonAttribute> attributes = null;
61
        
62
        @Field
63
        private String gender;
64
        
65

66
        @Field(analyze = Analyze.YES)
67
        @DateBridge(encoding = EncodingType.STRING, resolution = Resolution.DAY)
68
        private Date birthdate;
69
        
70
        private Date birthtime;
71
        
72
        private Boolean birthdateEstimated = false;
1✔
73
        
74
        private Boolean deathdateEstimated = false;
1✔
75
        
76
        @Field
1✔
77
        private Boolean dead = false;
1✔
78
        
79
        private Date deathDate;
80
        
81
        private Concept causeOfDeath;
82
        
83
        private String causeOfDeathNonCoded;
84
        
85
        private User personCreator;
86
        
87
        private Date personDateCreated;
88
        
89
        private User personChangedBy;
90
        
91
        private Date personDateChanged;
92
        
93
        private Boolean personVoided = false;
1✔
94
        
95
        private User personVoidedBy;
96
        
97
        private Date personDateVoided;
98
        
99
        private String personVoidReason;
100
        
101
        @Field
102
        private boolean isPatient;
103
        
104
        /**
105
         * Convenience map from PersonAttributeType.name to PersonAttribute.<br>
106
         * <br>
107
         * This is "cached" for each user upon first load. When an attribute is changed, the cache is
108
         * cleared and rebuilt on next access.
109
         */
110
        @Transient
1✔
111
        Map<String, PersonAttribute> attributeMap = null;
112
        
113
        @Transient
1✔
114
        private Map<String, PersonAttribute> allAttributeMap = null;
115
        
116
        /**
117
         * default empty constructor
118
         */
119
        public Person() {
1✔
120
        }
1✔
121
        
122
        /**
123
         * This constructor is used to build a new Person object copy from another person object
124
         * (usually a patient or a user subobject). All attributes are copied over to the new object.
125
         * NOTE! All child collection objects are copied as pointers, each individual element is not
126
         * copied. <br>
127
         *
128
         * @param person Person to create this person object from
129
         */
130
        public Person(Person person) {
1✔
131
                if (person == null) {
1✔
132
                        return;
×
133
                }
134
                
135
                personId = person.getPersonId();
1✔
136
                setUuid(person.getUuid());
1✔
137
                addresses = person.getAddresses();
1✔
138
                names = person.getNames();
1✔
139
                attributes = person.getAttributes();
1✔
140
                
141
                gender = person.getGender();
1✔
142
                birthdate = person.getBirthdate();
1✔
143
                birthtime = person.getBirthDateTime();
1✔
144
                birthdateEstimated = person.getBirthdateEstimated();
1✔
145
                deathdateEstimated = person.getDeathdateEstimated();
1✔
146
                dead = person.getDead();
1✔
147
                deathDate = person.getDeathDate();
1✔
148
                causeOfDeath = person.getCauseOfDeath();
1✔
149
                causeOfDeathNonCoded = person.getCauseOfDeathNonCoded();
1✔
150
                // base creator/voidedBy/changedBy info is not copied here
151
                // because that is specific to and will be recreated
152
                // by the subobject upon save
153
                
154
                setPersonCreator(person.getPersonCreator());
1✔
155
                setPersonDateCreated(person.getPersonDateCreated());
1✔
156
                setPersonChangedBy(person.getPersonChangedBy());
1✔
157
                setPersonDateChanged(person.getPersonDateChanged());
1✔
158
                setPersonVoided(person.getPersonVoided());
1✔
159
                setPersonVoidedBy(person.getPersonVoidedBy());
1✔
160
                setPersonDateVoided(person.getPersonDateVoided());
1✔
161
                setPersonVoidReason(person.getPersonVoidReason());
1✔
162
                
163
                setPatient(person.getIsPatient());
1✔
164
        }
1✔
165
        
166
        /**
167
         * Default constructor taking in the primary key personId value
168
         * 
169
         * @param personId Integer internal id for this person
170
         * <strong>Should</strong> set person id
171
         */
172
        public Person(Integer personId) {
1✔
173
                this.personId = personId;
1✔
174
        }
1✔
175
        
176
        // Property accessors
177
        
178
        /**
179
         * @return Returns the personId.
180
         */
181
        public Integer getPersonId() {
182
                return personId;
1✔
183
        }
184
        
185
        /**
186
         * @param personId The personId to set.
187
         */
188
        public void setPersonId(Integer personId) {
189
                this.personId = personId;
1✔
190
        }
1✔
191
        
192
        /**
193
         * @return person's gender
194
         */
195
        public String getGender() {
196
                return this.gender;
1✔
197
        }
198
        
199
        /**
200
         * @param gender person's gender
201
         */
202
        public void setGender(String gender) {
203
                this.gender = gender;
1✔
204
        }
1✔
205
        
206
        /**
207
         * @return person's date of birth
208
         */
209
        public Date getBirthdate() {
210
                return this.birthdate;
1✔
211
        }
212
        
213
        /**
214
         * @param birthdate person's date of birth
215
         */
216
        public void setBirthdate(Date birthdate) {
217
                this.birthdate = birthdate;
1✔
218
        }
1✔
219
        
220
        /**
221
         * @return true if person's birthdate is estimated
222
         * @deprecated as of 2.0, use {@link #getBirthdateEstimated()}
223
         */
224
        @Deprecated
225
        @JsonIgnore
226
        public Boolean isBirthdateEstimated() {
227
                return getBirthdateEstimated();
1✔
228
        }
229
        
230
        public Boolean getBirthdateEstimated() {
231
                return birthdateEstimated;
1✔
232
        }
233
        
234
        /**
235
         * @param birthdateEstimated true if person's birthdate is estimated
236
         */
237
        public void setBirthdateEstimated(Boolean birthdateEstimated) {
238
                this.birthdateEstimated = birthdateEstimated;
1✔
239
        }
1✔
240
        
241
        public Boolean getDeathdateEstimated() {
242
                return this.deathdateEstimated;
1✔
243
        }
244
        
245
        /**
246
         * @param deathdateEstimated true if person's deathdate is estimated
247
         */
248
        public void setDeathdateEstimated(Boolean deathdateEstimated) {
249
                this.deathdateEstimated = deathdateEstimated;
1✔
250
        }
1✔
251
        
252
        /**
253
         * @param birthtime person's time of birth
254
         */
255
        public void setBirthtime(Date birthtime) {
256
                this.birthtime = birthtime;
1✔
257
        }
1✔
258
        
259
        /**
260
         * @return person's time of birth with the date portion set to the date from person's birthdate
261
         */
262
        public Date getBirthDateTime() {
263
                if (birthdate != null && birthtime != null) {
1✔
264
                        String birthDateString = new SimpleDateFormat("yyyy-MM-dd").format(birthdate);
1✔
265
                        String birthTimeString = new SimpleDateFormat("HH:mm:ss").format(birthtime);
1✔
266
                        
267
                        try {
268
                                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(birthDateString + " " + birthTimeString);
1✔
269
                        }
270
                        catch (ParseException e) {
×
271
                                log.error("Failed to parse birth date string", e);
×
272
                        }
273
                }
274
                return null;
1✔
275
        }
276
        
277
        /**
278
         * @return person's time of birth.
279
         */
280
        public Date getBirthtime() {
281
                return this.birthtime;
1✔
282
        }
283
        
284
        /**
285
         * @return Returns the death status.
286
         * @deprecated as of 2.0, use {@link #getDead()}
287
         */
288
        @Deprecated
289
        @JsonIgnore
290
        public Boolean isDead() {
291
                return getDead();
1✔
292
        }
293
        
294
        /**
295
         * @return Returns the death status.
296
         */
297
        public Boolean getDead() {
298
                return dead;
1✔
299
        }
300
        
301
        /**
302
         * @param dead The dead to set.
303
         */
304
        public void setDead(Boolean dead) {
305
                this.dead = dead;
1✔
306
        }
1✔
307
        
308
        /**
309
         * @return date of person's death
310
         */
311
        public Date getDeathDate() {
312
                return this.deathDate;
1✔
313
        }
314
        
315
        /**
316
         * @param deathDate date of person's death
317
         */
318
        public void setDeathDate(Date deathDate) {
319
                this.deathDate = deathDate;
1✔
320
                if (deathDate != null) {
1✔
321
                        setDead(true);
1✔
322
                }
323
        }
1✔
324
        
325
        /**
326
         * @return cause of person's death
327
         */
328
        public Concept getCauseOfDeath() {
329
                return this.causeOfDeath;
1✔
330
        }
331
        
332
        /**
333
         * @param causeOfDeath cause of person's death
334
         */
335
        public void setCauseOfDeath(Concept causeOfDeath) {
336
                this.causeOfDeath = causeOfDeath;
1✔
337
        }
1✔
338
        
339
        /**
340
         * This method returns the non coded cause of death
341
         * 
342
         * @return non coded cause of death
343
         * @since 2.2.0
344
         */
345
        public String getCauseOfDeathNonCoded() {
346
                return this.causeOfDeathNonCoded;
1✔
347
        }
348
        
349
        /**
350
         * This method sets the non coded cause of death with the value given as parameter
351
         * 
352
         * @param causeOfDeathNonCoded is a String that describes as text the cause of death
353
         * @since 2.2.0
354
         * <strong>Should</strong> not fail with null causeOfDeathNonCoded
355
         * <strong>Should</strong> set the attribute causeOfDeathNonCoded with the given parameter
356
         */
357
        public void setCauseOfDeathNonCoded(String causeOfDeathNonCoded) {
358
                this.causeOfDeathNonCoded = causeOfDeathNonCoded;
1✔
359
        }
1✔
360
        
361
        /**
362
         * @return list of known addresses for person
363
         * @see org.openmrs.PersonAddress
364
         * <strong>Should</strong> not get voided addresses
365
         * <strong>Should</strong> not fail with null addresses
366
         */
367
        public Set<PersonAddress> getAddresses() {
368
                if (addresses == null) {
1✔
369
                        addresses = new TreeSet<>();
1✔
370
                }
371
                return this.addresses;
1✔
372
        }
373
        
374
        /**
375
         * @param addresses Set&lt;PersonAddress&gt; list of known addresses for person
376
         * @see org.openmrs.PersonAddress
377
         */
378
        public void setAddresses(Set<PersonAddress> addresses) {
379
                this.addresses = addresses;
1✔
380
        }
1✔
381
        
382
        /**
383
         * @return all known names for person
384
         * @see org.openmrs.PersonName
385
         * <strong>Should</strong> not get voided names
386
         * <strong>Should</strong> not fail with null names
387
         */
388
        public Set<PersonName> getNames() {
389
                if (names == null) {
1✔
390
                        names = new TreeSet<>();
1✔
391
                }
392
                return this.names;
1✔
393
        }
394
        
395
        /**
396
         * @param names update all known names for person
397
         * @see org.openmrs.PersonName
398
         */
399
        public void setNames(Set<PersonName> names) {
400
                this.names = names;
1✔
401
        }
1✔
402
        
403
        /**
404
         * @return all known attributes for person
405
         * @see org.openmrs.PersonAttribute
406
         * <strong>Should</strong> not get voided attributes
407
         * <strong>Should</strong> not fail with null attributes
408
         */
409
        public Set<PersonAttribute> getAttributes() {
410
                if (attributes == null) {
1✔
411
                        attributes = new TreeSet<>();
1✔
412
                }
413
                return this.attributes;
1✔
414
        }
415
        
416
        /**
417
         * Returns only the non-voided attributes for this person
418
         * 
419
         * @return list attributes
420
         * <strong>Should</strong> not get voided attributes
421
         * <strong>Should</strong> not fail with null attributes
422
         */
423
        public List<PersonAttribute> getActiveAttributes() {
424
                List<PersonAttribute> attrs = new ArrayList<>();
1✔
425
                for (PersonAttribute attr : getAttributes()) {
1✔
426
                        if (!attr.getVoided()) {
1✔
427
                                attrs.add(attr);
1✔
428
                        }
429
                }
1✔
430
                return attrs;
1✔
431
        }
432
        
433
        /**
434
         * @param attributes update all known attributes for person
435
         * @see org.openmrs.PersonAttribute
436
         */
437
        public void setAttributes(Set<PersonAttribute> attributes) {
438
                this.attributes = attributes;
1✔
439
                attributeMap = null;
1✔
440
                allAttributeMap = null;
1✔
441
        }
1✔
442
        
443
        // Convenience methods
444
        
445
        /**
446
         * Convenience method to add the <code>attribute</code> to this person's attribute list if the
447
         * attribute doesn't exist already.<br>
448
         * <br>
449
         * Voids any current attribute with type = <code>newAttribute.getAttributeType()</code><br>
450
         * <br>
451
         * NOTE: This effectively limits persons to only one attribute of any given type **
452
         * 
453
         * @param newAttribute PersonAttribute to add to the Person
454
         * <strong>Should</strong> fail when new attribute exist
455
         * <strong>Should</strong> fail when new atribute are the same type with same value
456
         * <strong>Should</strong> void old attribute when new attribute are the same type with different value
457
         * <strong>Should</strong> remove attribute when old attribute are temporary
458
         * <strong>Should</strong> not save an attribute with a null value
459
         * <strong>Should</strong> not save an attribute with a blank string value
460
         * <strong>Should</strong> void old attribute when a null or blank string value is added
461
         */
462
        public void addAttribute(PersonAttribute newAttribute) {
463
                newAttribute.setPerson(this);
1✔
464
                boolean newIsNull = !StringUtils.hasText(newAttribute.getValue());
1✔
465
                
466
                for (PersonAttribute currentAttribute : getActiveAttributes()) {
1✔
467
                        if (currentAttribute.equals(newAttribute)) {
1✔
468
                                // if we have the same PersonAttributeId, don't add the new attribute
469
                                return;
1✔
470
                        } else if (currentAttribute.getAttributeType().equals(newAttribute.getAttributeType())) {
1✔
471
                                if (currentAttribute.getValue() != null && currentAttribute.getValue().equals(newAttribute.getValue())) {
1✔
472
                                        // this person already has this attribute
473
                                        return;
1✔
474
                                }
475
                                
476
                                // if the to-be-added attribute isn't already voided itself
477
                                // and if we have the same type, different value
478
                                if (!newAttribute.getVoided() || newIsNull) {
1✔
479
                                        if (currentAttribute.getCreator() != null) {
1✔
480
                                                currentAttribute.voidAttribute("New value: " + newAttribute.getValue());
1✔
481
                                        } else {
482
                                                // remove the attribute if it was just temporary (didn't have a creator
483
                                                // attached to it yet)
484
                                                removeAttribute(currentAttribute);
×
485
                                        }
486
                                }
487
                        }
488
                }
1✔
489
                attributeMap = null;
1✔
490
                allAttributeMap = null;
1✔
491
                if (!OpenmrsUtil.collectionContains(attributes, newAttribute) && !newIsNull) {
1✔
492
                        attributes.add(newAttribute);
1✔
493
                }
494
        }
1✔
495
        
496
        /**
497
         * Convenience method to get the <code>attribute</code> from this person's attribute list if the
498
         * attribute exists already.
499
         * 
500
         * @param attribute
501
         * <strong>Should</strong> not fail when person attribute is null
502
         * <strong>Should</strong> not fail when person attribute is not exist
503
         * <strong>Should</strong> remove attribute when exist
504
         */
505
        public void removeAttribute(PersonAttribute attribute) {
506
                if (attributes != null && attributes.remove(attribute)) {
1✔
507
                        attributeMap = null;
1✔
508
                        allAttributeMap = null;
1✔
509
                }
510
        }
1✔
511
        
512
        /**
513
         * Convenience Method to return the first non-voided person attribute matching a person
514
         * attribute type. <br>
515
         * <br>
516
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given
517
         * {@link PersonAttributeType}, the given {@link PersonAttributeType} is null, or this person
518
         * has no attributes.
519
         * 
520
         * @param pat the PersonAttributeType to look for (can be a stub, see
521
         *            {@link PersonAttributeType#equals(Object)} for how its compared)
522
         * @return PersonAttribute that matches the given type
523
         * <strong>Should</strong> not fail when attribute type is null
524
         * <strong>Should</strong> not return voided attribute
525
         * <strong>Should</strong> return null when existing PersonAttributeType is voided
526
         */
527
        public PersonAttribute getAttribute(PersonAttributeType pat) {
528
                if (pat != null) {
1✔
529
                        for (PersonAttribute attribute : getAttributes()) {
1✔
530
                                if (pat.equals(attribute.getAttributeType()) && !attribute.getVoided()) {
1✔
531
                                        return attribute;
×
532
                                }
533
                        }
1✔
534
                }
535
                return null;
1✔
536
        }
537
        
538
        /**
539
         * Convenience method to get this person's first attribute that has a PersonAttributeType.name
540
         * equal to <code>attributeName</code>.<br>
541
         * <br>
542
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given type
543
         * name, the given name is null, or this person has no attributes.
544
         * 
545
         * @param attributeName the name string to match on
546
         * @return PersonAttribute whose {@link PersonAttributeType#getName()} matchs the given name
547
         *         string
548
         * <strong>Should</strong> return person attribute based on attributeName
549
         * <strong>Should</strong> return null if AttributeName is voided
550
         */
551
        public PersonAttribute getAttribute(String attributeName) {
552
                if (attributeName != null) {
1✔
553
                        for (PersonAttribute attribute : getAttributes()) {
1✔
554
                                PersonAttributeType type = attribute.getAttributeType();
1✔
555
                                if (type != null && attributeName.equals(type.getName()) && !attribute.getVoided()) {
1✔
556
                                        return attribute;
1✔
557
                                }
558
                        }
1✔
559
                }
560
                
561
                return null;
1✔
562
        }
563
        
564
        /**
565
         * Convenience method to get this person's first attribute that has a PersonAttributeTypeId
566
         * equal to <code>attributeTypeId</code>.<br>
567
         * <br>
568
         * Returns null if this person has no non-voided {@link PersonAttribute} with the given type id
569
         * or this person has no attributes.<br>
570
         * <br>
571
         * The given id cannot be null.
572
         * 
573
         * @param attributeTypeId the id of the {@link PersonAttributeType} to look for
574
         * @return PersonAttribute whose {@link PersonAttributeType#getId()} equals the given Integer id
575
         * <strong>Should</strong> return PersonAttribute based on attributeTypeId
576
         * <strong>Should</strong> return null when existing personAttribute with matching attribute type id is voided
577
         */
578
        public PersonAttribute getAttribute(Integer attributeTypeId) {
579
                for (PersonAttribute attribute : getActiveAttributes()) {
1✔
580
                        if (attributeTypeId.equals(attribute.getAttributeType().getPersonAttributeTypeId())) {
1✔
581
                                return attribute;
1✔
582
                        }
583
                }
1✔
584
                return null;
1✔
585
        }
586
        
587
        /**
588
         * Convenience method to get all of this person's attributes that have a
589
         * PersonAttributeType.name equal to <code>attributeName</code>.
590
         * 
591
         * @param attributeName
592
         * <strong>Should</strong> return all PersonAttributes with matching attributeType names
593
         */
594
        public List<PersonAttribute> getAttributes(String attributeName) {
595
                List<PersonAttribute> ret = new ArrayList<>();
1✔
596
                
597
                for (PersonAttribute attribute : getActiveAttributes()) {
1✔
598
                        PersonAttributeType type = attribute.getAttributeType();
1✔
599
                        if (type != null && attributeName.equals(type.getName())) {
1✔
600
                                ret.add(attribute);
1✔
601
                        }
602
                }
1✔
603
                
604
                return ret;
1✔
605
        }
606
        
607
        /**
608
         * Convenience method to get all of this person's attributes that have a PersonAttributeType.id
609
         * equal to <code>attributeTypeId</code>.
610
         * 
611
         * @param attributeTypeId
612
         * <strong>Should</strong> return empty list when matching personAttribute by id is voided
613
         * <strong>Should</strong> return list of person attributes based on AttributeTypeId
614
         */
615
        public List<PersonAttribute> getAttributes(Integer attributeTypeId) {
616
                List<PersonAttribute> ret = new ArrayList<>();
1✔
617
                
618
                for (PersonAttribute attribute : getActiveAttributes()) {
1✔
619
                        if (attributeTypeId.equals(attribute.getAttributeType().getPersonAttributeTypeId())) {
1✔
620
                                ret.add(attribute);
1✔
621
                        }
622
                }
1✔
623
                
624
                return ret;
1✔
625
        }
626
        
627
        /**
628
         * Convenience method to get all of this person's attributes that have a PersonAttributeType
629
         * equal to <code>personAttributeType</code>.
630
         * 
631
         * @param personAttributeType
632
         */
633
        public List<PersonAttribute> getAttributes(PersonAttributeType personAttributeType) {
634
                List<PersonAttribute> ret = new ArrayList<>();
×
635
                for (PersonAttribute attribute : getAttributes()) {
×
636
                        if (personAttributeType.equals(attribute.getAttributeType()) && !attribute.getVoided()) {
×
637
                                ret.add(attribute);
×
638
                        }
639
                }
×
640
                return ret;
×
641
        }
642
        
643
        /**
644
         * Convenience method to get this person's active attributes in map form: &lt;String,
645
         * PersonAttribute&gt;.
646
         */
647
        public Map<String, PersonAttribute> getAttributeMap() {
648
                if (attributeMap != null) {
×
649
                        return attributeMap;
×
650
                }
651
                
652
                log.debug("Current Person Attributes: \n{}", printAttributes());
×
653
                
654
                attributeMap = new HashMap<>();
×
655
                for (PersonAttribute attribute : getActiveAttributes()) {
×
656
                        attributeMap.put(attribute.getAttributeType().getName(), attribute);
×
657
                }
×
658
                
659
                return attributeMap;
×
660
        }
661
        
662
        /**
663
         * Convenience method to get all of this person's attributes (including voided ones) in map
664
         * form: &lt;String, PersonAttribute&gt;.
665
         * 
666
         * @return All person's attributes in map form
667
         * @since 1.12
668
         */
669
        public Map<String, PersonAttribute> getAllAttributeMap() {
670
                if (allAttributeMap != null) {
×
671
                        return allAttributeMap;
×
672
                }
673
                
674
                log.debug("Current Person Attributes: \n{}", printAttributes());
×
675
                
676
                allAttributeMap = new HashMap<>();
×
677
                for (PersonAttribute attribute : getAttributes()) {
×
678
                        allAttributeMap.put(attribute.getAttributeType().getName(), attribute);
×
679
                }
×
680
                
681
                return allAttributeMap;
×
682
        }
683
        
684
        /**
685
         * Convenience method for viewing all of the person's current attributes
686
         * 
687
         * @return Returns a string with all the attributes
688
         */
689
        public String printAttributes() {
690
                StringBuilder s = new StringBuilder("");
×
691
                
692
                for (PersonAttribute attribute : getAttributes()) {
×
693
                        s.append(attribute.getAttributeType()).append(" : ").append(attribute.getValue()).append(" : voided? ")
×
694
                                .append(attribute.getVoided()).append("\n");
×
695
                }
×
696
                
697
                return s.toString();
×
698
        }
699
        
700
        /**
701
         * Convenience method to add the <code>name</code> to this person's name list if the name
702
         * doesn't exist already.
703
         * 
704
         * @param name
705
         */
706
        public void addName(PersonName name) {
707
                if (name != null) {
1✔
708
                        name.setPerson(this);
1✔
709
                        if (names == null) {
1✔
710
                                names = new TreeSet<>();
1✔
711
                        }
712
                        if (!OpenmrsUtil.collectionContains(names, name)) {
1✔
713
                                names.add(name);
1✔
714
                        }
715
                }
716
        }
1✔
717
        
718
        /**
719
         * Convenience method remove the <code>name</code> from this person's name list if the name
720
         * exists already.
721
         * 
722
         * @param name
723
         */
724
        public void removeName(PersonName name) {
725
                if (names != null) {
1✔
726
                        names.remove(name);
1✔
727
                }
728
        }
1✔
729
        
730
        /**
731
         * Convenience method to add the <code>address</code> to this person's address list if the
732
         * address doesn't exist already.
733
         * 
734
         * @param address
735
         * <strong>Should</strong> not add a person address with blank fields
736
         */
737
        public void addAddress(PersonAddress address) {
738
                if (address != null) {
1✔
739
                        address.setPerson(this);
1✔
740
                        if (addresses == null) {
1✔
741
                                addresses = new TreeSet<>();
1✔
742
                        }
743
                        if (!OpenmrsUtil.collectionContains(addresses, address) && !address.isBlank()) {
1✔
744
                                addresses.add(address);
1✔
745
                        }
746
                }
747
        }
1✔
748
        
749
        /**
750
         * Convenience method to remove the <code>address</code> from this person's address list if the
751
         * address exists already.
752
         * 
753
         * @param address
754
         */
755
        public void removeAddress(PersonAddress address) {
756
                if (addresses != null) {
1✔
757
                        addresses.remove(address);
1✔
758
                }
759
        }
1✔
760
        
761
        /**
762
         * Convenience method to get the {@link PersonName} object that is marked as "preferred". <br>
763
         * <br>
764
         * If two names are marked as preferred (or no names), the database ordering comes into effect
765
         * and the one that was created most recently will be returned. <br>
766
         * <br>
767
         * This method will never return a voided name, even if it is marked as preferred. <br>
768
         * <br>
769
         * Null is returned if this person has no names or all voided names.
770
         * 
771
         * @return the "preferred" person name.
772
         * @see #getNames()
773
         * @see PersonName#getPreferred()
774
         * <strong>Should</strong> get preferred and not-voided person name if exist
775
         * <strong>Should</strong> get not-voided person name if preferred address does not exist
776
         * <strong>Should</strong> get voided person address if person is voided and not-voided address does not exist
777
         * <strong>Should</strong> return null if person is not-voided and have voided names
778
         */
779
        public PersonName getPersonName() {
780
                // normally the DAO layer returns these in the correct order, i.e. preferred and non-voided first, but it's possible that someone
781
                // has fetched a Person, changed their names around, and then calls this method, so we have to be careful.
782
                if (getNames() != null && !getNames().isEmpty()) {
1✔
783
                        for (PersonName name : getNames()) {
1✔
784
                                if (name.getPreferred() && !name.getVoided()) {
1✔
785
                                        return name;
1✔
786
                                }
787
                        }
1✔
788
                        for (PersonName name : getNames()) {
1✔
789
                                if (!name.getVoided()) {
1✔
790
                                        return name;
1✔
791
                                }
792
                        }
1✔
793
                        
794
                        if (getVoided()) {
1✔
795
                                return getNames().iterator().next();
1✔
796
                        }
797
                }
798
                return null;
1✔
799
        }
800
        
801
        /**
802
         * Convenience method to get the given name attribute on this person's preferred PersonName
803
         * 
804
         * @return String given name of the person
805
         */
806
        public String getGivenName() {
807
                PersonName personName = getPersonName();
1✔
808
                if (personName == null) {
1✔
809
                        return "";
×
810
                } else {
811
                        return personName.getGivenName();
1✔
812
                }
813
        }
814
        
815
        /**
816
         * Convenience method to get the middle name attribute on this person's preferred PersonName
817
         * 
818
         * @return String middle name of the person
819
         */
820
        public String getMiddleName() {
821
                PersonName personName = getPersonName();
1✔
822
                if (personName == null) {
1✔
823
                        return "";
×
824
                } else {
825
                        return personName.getMiddleName();
1✔
826
                }
827
        }
828
        
829
        /**
830
         * Convenience method to get the family name attribute on this person's preferred PersonName
831
         * 
832
         * @return String family name of the person
833
         */
834
        public String getFamilyName() {
835
                PersonName personName = getPersonName();
1✔
836
                if (personName == null) {
1✔
837
                        return "";
×
838
                } else {
839
                        return personName.getFamilyName();
1✔
840
                }
841
        }
842
        
843
        /**
844
         * Convenience method to get the {@link PersonAddress} object that is marked as "preferred". <br>
845
         * <br>
846
         * If two addresses are marked as preferred (or no addresses), the database ordering comes into
847
         * effect and the one that was created most recently will be returned. <br>
848
         * <br>
849
         * This method will never return a voided address, even if it is marked as preferred. <br>
850
         * <br>
851
         * Null is returned if this person has no addresses or all voided addresses.
852
         * 
853
         * @return the "preferred" person address.
854
         * @see #getAddresses()
855
         * @see PersonAddress#getPreferred()
856
         * <strong>Should</strong> get preferred and not-voided person address if exist
857
         * <strong>Should</strong> get not-voided person address if preferred address does not exist
858
         * <strong>Should</strong> get voided person address if person is voided and not-voided address does not exist
859
         * <strong>Should</strong> return null if person is not-voided and have voided address
860
         */
861
        public PersonAddress getPersonAddress() {
862
                // normally the DAO layer returns these in the correct order, i.e. preferred and non-voided first, but it's possible that someone
863
                // has fetched a Person, changed their addresses around, and then calls this method, so we have to be careful.
864
                if (getAddresses() != null && !getAddresses().isEmpty()) {
1✔
865
                        for (PersonAddress addr : getAddresses()) {
1✔
866
                                if (addr.getPreferred() && !addr.getVoided()) {
1✔
867
                                        return addr;
1✔
868
                                }
869
                        }
1✔
870
                        for (PersonAddress addr : getAddresses()) {
1✔
871
                                if (!addr.getVoided()) {
1✔
872
                                        return addr;
1✔
873
                                }
874
                        }
1✔
875
                        
876
                        if (getVoided()) {
1✔
877
                                return getAddresses().iterator().next();
1✔
878
                        }
879
                }
880
                return null;
1✔
881
        }
882
        
883
        /**
884
         * Convenience method to calculate this person's age based on the birthdate For a person who
885
         * lived 1990 to 2000, age would be -5 in 1985, 5 in 1995, 10 in 2000, and 10 2010.
886
         * 
887
         * @return Returns age as an Integer.
888
         * <strong>Should</strong> get correct age after death
889
         */
890
        public Integer getAge() {
891
                return getAge(null);
1✔
892
        }
893
        
894
        /**
895
         * Convenience method: calculates the person's age on a given date based on the birthdate
896
         * 
897
         * @param onDate (null defaults to today)
898
         * @return int value of the person's age
899
         * <strong>Should</strong> get age before birthday
900
         * <strong>Should</strong> get age on birthday with no minutes defined
901
         * <strong>Should</strong> get age on birthday with minutes defined
902
         * <strong>Should</strong> get age after birthday
903
         * <strong>Should</strong> get age after death
904
         * <strong>Should</strong> get age with given date after death
905
         * <strong>Should</strong> get age with given date before death
906
         * <strong>Should</strong> get age with given date before birth
907
         */
908
        public Integer getAge(Date onDate) {
909
                if (birthdate == null) {
1✔
910
                        return null;
1✔
911
                }
912
                
913
                // Use default end date as today.
914
                Calendar today = Calendar.getInstance();
1✔
915
                // But if given, use the given date.
916
                if (onDate != null) {
1✔
917
                        today.setTime(onDate);
1✔
918
                }
919
                
920
                // If date given is after date of death then use date of death as end date
921
                if (getDeathDate() != null && today.getTime().after(getDeathDate())) {
1✔
922
                        today.setTime(getDeathDate());
1✔
923
                }
924
                
925
                Calendar bday = Calendar.getInstance();
1✔
926
                bday.setTime(birthdate);
1✔
927
                
928
                int age = today.get(Calendar.YEAR) - bday.get(Calendar.YEAR);
1✔
929
                
930
                // Adjust age when today's date is before the person's birthday
931
                int todaysMonth = today.get(Calendar.MONTH);
1✔
932
                int bdayMonth = bday.get(Calendar.MONTH);
1✔
933
                int todaysDay = today.get(Calendar.DAY_OF_MONTH);
1✔
934
                int bdayDay = bday.get(Calendar.DAY_OF_MONTH);
1✔
935
                
936
                if (todaysMonth < bdayMonth) {
1✔
UNCOV
937
                        age--;
×
938
                } else if (todaysMonth == bdayMonth && todaysDay < bdayDay) {
1✔
939
                        // we're only comparing on month and day, not minutes, etc
940
                        age--;
1✔
941
                }
942
                
943
                return age;
1✔
944
        }
945
        
946
        /**
947
         * Convenience method: sets a person's birth date from an age as of the given date Also sets
948
         * flag indicating that the birth date is inexact. This sets the person's birth date to January
949
         * 1 of the year that matches this age and date
950
         * 
951
         * @param age (the age to set)
952
         * @param ageOnDate (null defaults to today)
953
         */
954
        public void setBirthdateFromAge(int age, Date ageOnDate) {
955
                Calendar c = Calendar.getInstance();
1✔
956
                c.setTime(ageOnDate == null ? new Date() : ageOnDate);
1✔
957
                c.set(Calendar.DATE, 1);
1✔
958
                c.set(Calendar.MONTH, Calendar.JANUARY);
1✔
959
                c.add(Calendar.YEAR, -1 * age);
1✔
960
                setBirthdate(c.getTime());
1✔
961
                setBirthdateEstimated(true);
1✔
962
                
963
        }
1✔
964
        
965
        public User getPersonChangedBy() {
966
                return personChangedBy;
1✔
967
        }
968
        
969
        public void setPersonChangedBy(User changedBy) {
970
                this.personChangedBy = changedBy;
1✔
971
                this.setChangedBy(changedBy);
1✔
972
        }
1✔
973
        
974
        public Date getPersonDateChanged() {
975
                return personDateChanged;
1✔
976
        }
977
        
978
        public void setPersonDateChanged(Date dateChanged) {
979
                this.personDateChanged = dateChanged;
1✔
980
                this.setDateChanged(dateChanged);
1✔
981
        }
1✔
982
        
983
        public User getPersonCreator() {
984
                return personCreator;
1✔
985
        }
986
        
987
        public void setPersonCreator(User creator) {
988
                this.personCreator = creator;
1✔
989
                this.setCreator(creator);
1✔
990
        }
1✔
991
        
992
        public Date getPersonDateCreated() {
993
                return personDateCreated;
1✔
994
        }
995
        
996
        public void setPersonDateCreated(Date dateCreated) {
997
                this.personDateCreated = dateCreated;
1✔
998
                this.setDateCreated(dateCreated);
1✔
999
        }
1✔
1000
        
1001
        public Date getPersonDateVoided() {
1002
                return personDateVoided;
1✔
1003
        }
1004
        
1005
        public void setPersonDateVoided(Date dateVoided) {
1006
                this.personDateVoided = dateVoided;
1✔
1007
                this.setDateVoided(dateVoided);
1✔
1008
        }
1✔
1009
        
1010
        public void setPersonVoided(Boolean voided) {
1011
                this.personVoided = voided;
1✔
1012
                this.setVoided(voided);
1✔
1013
        }
1✔
1014
        
1015
        public Boolean getPersonVoided() {
1016
                return personVoided;
1✔
1017
        }
1018
        
1019
        /**
1020
         * @deprecated as of 2.0, use {@link #getPersonVoided()}
1021
         */
1022
        @Deprecated
1023
        @JsonIgnore
1024
        public Boolean isPersonVoided() {
1025
                return getPersonVoided();
×
1026
        }
1027
        
1028
        public User getPersonVoidedBy() {
1029
                return personVoidedBy;
1✔
1030
        }
1031
        
1032
        public void setPersonVoidedBy(User voidedBy) {
1033
                this.personVoidedBy = voidedBy;
1✔
1034
                this.setVoidedBy(voidedBy);
1✔
1035
        }
1✔
1036
        
1037
        public String getPersonVoidReason() {
1038
                return personVoidReason;
1✔
1039
        }
1040
        
1041
        public void setPersonVoidReason(String voidReason) {
1042
                this.personVoidReason = voidReason;
1✔
1043
                this.setVoidReason(voidReason);
1✔
1044
        }
1✔
1045
        
1046
        /**
1047
         * @return true/false whether this person is a patient or not
1048
         * @deprecated as of 2.0, use {@link #getIsPatient()}
1049
         */
1050
        @Deprecated
1051
        @JsonIgnore
1052
        public boolean isPatient() {
1053
                return getIsPatient();
1✔
1054
        }
1055
        
1056
        public boolean getIsPatient() {
1057
                return isPatient;
1✔
1058
        }
1059
        
1060
        /**
1061
         * This should only be set by the database layer by looking at whether a row exists in the
1062
         * patient table
1063
         * 
1064
         * @param isPatient whether this person is a patient or not
1065
         */
1066
        protected void setPatient(boolean isPatient) {
1067
                this.isPatient = isPatient;
1✔
1068
        }
1✔
1069
        
1070
        /**
1071
         * @see java.lang.Object#toString()
1072
         */
1073
        @Override
1074
        public String toString() {
1075
                return "Person(personId=" + personId + ")";
1✔
1076
        }
1077
        
1078
        /**
1079
         * @since 1.5
1080
         * @see org.openmrs.OpenmrsObject#getId()
1081
         */
1082
        @Override
1083
        public Integer getId() {
1084
                
1085
                return getPersonId();
1✔
1086
        }
1087
        
1088
        /**
1089
         * @since 1.5
1090
         * @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
1091
         */
1092
        @Override
1093
        public void setId(Integer id) {
1094
                setPersonId(id);
1✔
1095
                
1096
        }
1✔
1097
        
1098
}
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