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

openmrs / openmrs-core / 8606329231

08 Apr 2024 08:37PM CUT coverage: 64.712% (+0.03%) from 64.68%
8606329231

push

github

web-flow
github-actions(deps): bump actions/upload-artifact from 3 to 4 (#4615)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

22772 of 35190 relevant lines covered (64.71%)

0.65 hits per line

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

93.55
/api/src/main/java/org/openmrs/validator/PatientProgramValidator.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.validator;
11

12
import java.util.Date;
13
import java.util.HashSet;
14
import java.util.Set;
15

16
import org.openmrs.PatientProgram;
17
import org.openmrs.PatientState;
18
import org.openmrs.ProgramWorkflow;
19
import org.openmrs.annotation.Handler;
20
import org.openmrs.api.context.Context;
21
import org.openmrs.messagesource.MessageSourceService;
22
import org.openmrs.util.OpenmrsUtil;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25
import org.springframework.validation.Errors;
26
import org.springframework.validation.ValidationUtils;
27
import org.springframework.validation.Validator;
28

29
/**
30
 * This class validates a {@link PatientProgram} object
31
 *
32
 * @since 1.9
33
 */
34
@Handler(supports = { PatientProgram.class }, order = 50)
35
public class PatientProgramValidator implements Validator {
1✔
36
        
37
        private static final Logger log = LoggerFactory.getLogger(PatientProgramValidator.class);
1✔
38
        
39
        /**
40
         * @see org.springframework.validation.Validator#supports(java.lang.Class)
41
         */
42
        @Override
43
        public boolean supports(Class<?> c) {
44
                return PatientProgram.class.isAssignableFrom(c);
1✔
45
        }
46
        
47
        /**
48
         * Validates the given PatientProgram.
49
         *
50
         * @param obj The patient program to validate.
51
         * @param errors Errors
52
         * @see org.springframework.validation.Validator#validate(java.lang.Object,
53
         *      org.springframework.validation.Errors)
54
         * <strong>Should</strong> fail validation if obj is null
55
         * <strong>Should</strong> fail if the patient field is blank
56
         * <strong>Should</strong> fail if there is more than one patientState with the same states and startDates
57
         * <strong>Should</strong> fail if there is more than one state with a null start date in the same workflow
58
         * <strong>Should</strong> pass if the start date of the first patient state in the work flow is null
59
         * <strong>Should</strong> fail if any patient state has an end date before its start date
60
         * <strong>Should</strong> fail if the program property is null
61
         * <strong>Should</strong> fail if any patient states overlap each other in the same work flow
62
         * <strong>Should</strong> fail if a patientState has an invalid work flow state
63
         * <strong>Should</strong> fail if a patient program has duplicate states in the same work flow
64
         * <strong>Should</strong> fail if a patient is in multiple states in the same work flow
65
         * <strong>Should</strong> fail if a enrolled date is in future at the date it set
66
         * <strong>Should</strong> fail if a completion date is in future at the date it set
67
         * <strong>Should</strong> fail if a patient program has an enroll date after its completion
68
         * <strong>Should</strong> pass if a patient is in multiple states in different work flows
69
         * <strong>Should</strong> pass for a valid program
70
         * <strong>Should</strong> pass for patient states that have the same start dates in the same work flow
71
         * <strong>Should</strong> pass validation if field lengths are correct
72
         * <strong>Should</strong> fail validation if field lengths are not correct
73
         */
74
        @Override
75
        public void validate(Object obj, Errors errors) {
76
                log.debug("{}.validate...", this.getClass().getName());
1✔
77
                
78
                if (obj == null) {
1✔
79
                        throw new IllegalArgumentException("The parameter obj should not be null");
1✔
80
                }
81
                MessageSourceService mss = Context.getMessageSourceService();
1✔
82
                PatientProgram patientProgram = (PatientProgram) obj;
1✔
83
                ValidationUtils.rejectIfEmpty(errors, "patient", "error.required",
1✔
84
                    new Object[] { mss.getMessage("general.patient") });
1✔
85
                ValidationUtils.rejectIfEmpty(errors, "program", "error.required",
1✔
86
                    new Object[] { mss.getMessage("Program.program") });
1✔
87
                
88
                if (errors.hasErrors()) {
1✔
89
                        return;
1✔
90
                }
91
                
92
                ValidationUtils.rejectIfEmpty(errors, "dateEnrolled", "error.patientProgram.enrolledDateEmpty");
1✔
93
                
94
                Date today = new Date();
1✔
95
                if (patientProgram.getDateEnrolled() != null && today.before(patientProgram.getDateEnrolled())) {
1✔
96
                        errors.rejectValue("dateEnrolled", "error.patientProgram.enrolledDateDateCannotBeInFuture");
1✔
97
                }
98
                
99
                if (patientProgram.getDateCompleted() != null && today.before(patientProgram.getDateCompleted())) {
1✔
100
                        errors.rejectValue("dateCompleted", "error.patientProgram.completionDateCannotBeInFuture");
1✔
101
                }
102
                
103
                // if enrollment or complete date of program is in future or complete date has come before enroll date we should throw error
104
                if (patientProgram.getDateEnrolled() != null
1✔
105
                        && OpenmrsUtil.compareWithNullAsLatest(patientProgram.getDateCompleted(), patientProgram.getDateEnrolled()) < 0) {
1✔
106
                        errors.rejectValue("dateCompleted", "error.patientProgram.enrolledDateShouldBeBeforecompletionDate");
1✔
107
                }
108
                
109
                Set<ProgramWorkflow> workFlows = patientProgram.getProgram().getWorkflows();
1✔
110
                //Patient state validation is specific to a work flow
111
                for (ProgramWorkflow workFlow : workFlows) {
1✔
112
                        Set<PatientState> patientStates = patientProgram.getStates();
1✔
113
                        if (patientStates != null) {
1✔
114
                                //Set to store to keep track of unique valid state and start date combinations
115
                                Set<String> statesAndStartDates = new HashSet<>();
1✔
116
                                PatientState latestState = null;
1✔
117
                                boolean foundCurrentPatientState = false;
1✔
118
                                boolean foundStateWithNullStartDate = false;
1✔
119
                                for (PatientState patientState : patientStates) {
1✔
120
                                        if (patientState.getVoided()) {
1✔
121
                                                continue;
1✔
122
                                        }
123
                                        
124
                                        String missingRequiredFieldCode = null;
1✔
125
                                        //only the initial state can have a null start date
126
                                        if (patientState.getStartDate() == null) {
1✔
127
                                                if (foundStateWithNullStartDate) {
1✔
128
                                                        missingRequiredFieldCode = "general.dateStart";
1✔
129
                                                } else {
130
                                                        foundStateWithNullStartDate = true;
1✔
131
                                                }
132
                                        } else if (patientState.getState() == null) {
1✔
133
                                                missingRequiredFieldCode = "State.state";
1✔
134
                                        }
135
                                        
136
                                        if (missingRequiredFieldCode != null) {
1✔
137
                                                errors.rejectValue("states", "PatientState.error.requiredField", new Object[] { mss
1✔
138
                                                        .getMessage(missingRequiredFieldCode) }, null);
1✔
139
                                                return;
1✔
140
                                        }
141
                                        
142
                                        //state should belong to one of the workflows in the program
143
                                        // note that we are iterating over getAllWorkflows() here because we want to include
144
                                        // retired workflows, and the workflows variable does not include retired workflows
145
                                        boolean isValidPatientState = false;
1✔
146
                                        for (ProgramWorkflow wf : patientProgram.getProgram().getAllWorkflows()) {
1✔
147
                                                if (wf.getStates().contains(patientState.getState())) {
1✔
148
                                                        isValidPatientState = true;
1✔
149
                                                        break;
1✔
150
                                                }
151
                                        }
1✔
152
                                        
153
                                        if (!isValidPatientState) {
1✔
154
                                                errors.rejectValue("states", "PatientState.error.invalidPatientState",
1✔
155
                                                    new Object[] { patientState }, null);
156
                                                return;
1✔
157
                                        }
158
                                        
159
                                        //will validate it with other states in its workflow
160
                                        if (!patientState.getState().getProgramWorkflow().equals(workFlow)) {
1✔
161
                                                continue;
1✔
162
                                        }
163
                                        
164
                                        if (OpenmrsUtil.compareWithNullAsLatest(patientState.getEndDate(), patientState.getStartDate()) < 0) {
1✔
165
                                                errors.rejectValue("states", "PatientState.error.endDateCannotBeBeforeStartDate");
1✔
166
                                                return;
1✔
167
                                        } else if (statesAndStartDates.contains(patientState.getState().getUuid() + ""
1✔
168
                                                + patientState.getStartDate())) {
1✔
169
                                                // we already have a patient state with the same work flow state and start date
170
                                                errors.rejectValue("states", "PatientState.error.duplicatePatientStates");
1✔
171
                                                return;
1✔
172
                                        }
173
                                        
174
                                        //Ensure that the patient is only in one state at a given time
175
                                        if (!foundCurrentPatientState && patientState.getEndDate() == null) {
1✔
176
                                                foundCurrentPatientState = true;
1✔
177
                                        } else if (foundCurrentPatientState && patientState.getEndDate() == null) {
1✔
178
                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
1✔
179
                                                return;
1✔
180
                                        }
181
                                        
182
                                        if (latestState == null) {
1✔
183
                                                latestState = patientState;
1✔
184
                                        } else {
185
                                                if (patientState.compareTo(latestState) > 0) {
1✔
186
                                                        //patient should have already left this state since it is older
187
                                                        if (latestState.getEndDate() == null) {
1✔
188
                                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
×
189
                                                                return;
×
190
                                                        } else if (OpenmrsUtil.compareWithNullAsEarliest(patientState.getStartDate(), latestState
1✔
191
                                                                .getEndDate()) < 0) {
1✔
192
                                                                //current state was started before a previous state was ended
193
                                                                errors.rejectValue("states", "PatientProgram.error.foundOverlappingStates", new Object[] {
1✔
194
                                                                        patientState.getStartDate(), latestState.getEndDate() }, null);
1✔
195
                                                                return;
1✔
196
                                                        }
197
                                                        latestState = patientState;
1✔
198
                                                } else if (patientState.compareTo(latestState) < 0) {
1✔
199
                                                        //patient should have already left this state since it is older
200
                                                        if (patientState.getEndDate() == null) {
1✔
201
                                                                errors.rejectValue("states", "PatientProgram.error.cannotBeInMultipleStates");
×
202
                                                                return;
×
203
                                                        } else if (OpenmrsUtil.compareWithNullAsEarliest(latestState.getStartDate(), patientState
1✔
204
                                                                .getEndDate()) < 0) {
1✔
205
                                                                //latest state was started before a previous state was ended
206
                                                                errors.rejectValue("states", "PatientProgram.error.foundOverlappingStates");
×
207
                                                                return;
×
208
                                                        }
209
                                                }
210
                                        }
211
                                        
212
                                        statesAndStartDates.add(patientState.getState().getUuid() + "" + patientState.getStartDate());
1✔
213
                                }
1✔
214
                        }
215
                }
1✔
216
                ValidateUtil.validateFieldLengths(errors, obj.getClass(), "voidReason");
1✔
217
                //
218
        }
1✔
219
}
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

© 2025 Coveralls, Inc