Skip to content

Commit

Permalink
Merge pull request I-TECH-UW#1031 from mozzy11/develop
Browse files Browse the repository at this point in the history
Fix Patient ID validation
  • Loading branch information
mozzy11 authored May 3, 2024
2 parents 5242f4e + 53fb55c commit ff117b5
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 216 deletions.
34 changes: 18 additions & 16 deletions frontend/src/components/patient/CreatePatientForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,18 @@ function CreatePatientForm(props) {
const [nationalId, setNationalId] = useState(
props.selectedPatient.nationalId,
);
const [subjectNo, setSubjectNo] = useState(
props.selectedPatient.subjectNumber,
);
const handleNationalIdChange = (event) => {
const newValue = event.target.value;
setNationalId(newValue);
};

const handleSubjectNoChange = (event) => {
const newValue = event.target.value;
setSubjectNo(newValue);
};
const handleDatePickerChange = (values, ...e) => {
var patient = values;
patient.birthDateForDisplay = e[1];
Expand Down Expand Up @@ -244,8 +252,8 @@ function CreatePatientForm(props) {
const accessionNumberValidationResponse = (res, numberType, numberValue) => {
let error;
if (
res.status === false &&
props.selectedPatient.nationalId !== nationalId
res.status === false &&(props.selectedPatient.nationalId !== nationalId || props.selectedPatient.subjectNumber !== subjectNo)

) {
setNotificationVisible(true);
addNotification({
Expand Down Expand Up @@ -382,13 +390,6 @@ function CreatePatientForm(props) {
<Column lg={8} md={4} sm={4}>
<Field
name="subjectNumber"
validate={() => {
return handleSubjectNoValidation(
"subjectNumber",
"subjectNumberID",
values.subjectNumber,
);
}}
>
{({ field }) => (
<>
Expand All @@ -401,6 +402,14 @@ function CreatePatientForm(props) {
id={field.name}
invalid={errors.subjectNumber && touched.subjectNumber}
invalidText={errors.subjectNumber}
onMouseOut={() => {
handleSubjectNoValidation(
"subjectNumber",
"subjectNumberID",
values.subjectNumber,
);
}}
onChange={handleSubjectNoChange}
placeholder={intl.formatMessage({
id: "patient.information.healthid",
})}
Expand All @@ -412,13 +421,6 @@ function CreatePatientForm(props) {
<Column lg={8} md={4} sm={4}>
<Field
name="nationalId"
validate={() => {
return handleSubjectNoValidation(
"nationalId",
"nationalID",
values.nationalId,
);
}}
>
{({ field }) => (
<TextInput
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

Expand All @@ -14,15 +13,14 @@
import org.openelisglobal.common.controller.BaseController;
import org.openelisglobal.common.exception.LIMSRuntimeException;
import org.openelisglobal.common.log.LogEvent;
import org.openelisglobal.common.provider.query.PatientSearchResults;
import org.openelisglobal.common.util.ConfigurationProperties;
import org.openelisglobal.dataexchange.fhir.exception.FhirPersistanceException;
import org.openelisglobal.dataexchange.fhir.exception.FhirTransformationException;
import org.openelisglobal.dataexchange.fhir.service.FhirTransformService;
import org.openelisglobal.patient.action.IPatientUpdate.PatientUpdateStatus;
import org.openelisglobal.patient.action.bean.PatientManagementInfo;
import org.openelisglobal.patient.action.bean.PatientSearch;
import org.openelisglobal.patient.service.PatientService;
import org.openelisglobal.patient.validator.ValidatePatientInfo;
import org.openelisglobal.patient.valueholder.Patient;
import org.openelisglobal.patientidentity.service.PatientIdentityService;
import org.openelisglobal.patientidentity.valueholder.PatientIdentity;
Expand Down Expand Up @@ -70,10 +68,6 @@ public class PatientManagementController extends BaseController {
@Autowired
SamplePatientEntryFormValidator formValidator;

private static final String AMBIGUOUS_DATE_CHAR = ConfigurationProperties.getInstance()
.getPropertyValue(ConfigurationProperties.Property.AmbiguousDateHolder);
private static final String AMBIGUOUS_DATE_HOLDER = AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;

@Autowired
AddressPartService addressPartService;
@Autowired
Expand Down Expand Up @@ -167,7 +161,7 @@ public void cleanAndSetupRequestForm(SamplePatientEntryForm form, HttpServletReq
public void preparePatientData(Errors errors, HttpServletRequest request, PatientManagementInfo patientInfo,
Patient patient) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

validatePatientInfo(errors, patientInfo);
ValidatePatientInfo.validatePatientInfo(errors, patientInfo);
if (errors.hasErrors()) {
return;
}
Expand All @@ -188,60 +182,6 @@ public void preparePatientData(Errors errors, HttpServletRequest request, Patien

}

private void validatePatientInfo(Errors errors, PatientManagementInfo patientInfo) {
if (ConfigurationProperties.getInstance()
.isPropertyValueEqual(ConfigurationProperties.Property.ALLOW_DUPLICATE_SUBJECT_NUMBERS, "false")) {
String newSTNumber = org.apache.commons.validator.GenericValidator.isBlankOrNull(patientInfo.getSTnumber())
? null
: patientInfo.getSTnumber();
String newSubjectNumber = org.apache.commons.validator.GenericValidator
.isBlankOrNull(patientInfo.getSubjectNumber()) ? null : patientInfo.getSubjectNumber();
String newNationalId = org.apache.commons.validator.GenericValidator
.isBlankOrNull(patientInfo.getNationalId()) ? null : patientInfo.getNationalId();

List<PatientSearchResults> results = searchService.getSearchResults(null, null, newSTNumber,
newSubjectNumber, newNationalId, null, null, null, null, null);

if (!results.isEmpty()) {
for (PatientSearchResults result : results) {
if (!result.getPatientID().equals(patientInfo.getPatientPK())) {
if (newSTNumber != null && newSTNumber.equals(result.getSTNumber())) {
errors.reject("error.duplicate.STNumber", "error.duplicate.STNumber");
}
if (newSubjectNumber != null && newSubjectNumber.equals(result.getSubjectNumber())) {
errors.reject("error.duplicate.subjectNumber", "error.duplicate.subjectNumber");
}
if (newNationalId != null && newNationalId.equals(result.getNationalId())) {
errors.reject("error.duplicate.nationalId", "error.duplicate.nationalId");
}
}
}
}
}

validateBirthdateFormat(patientInfo, errors);

}

private void validateBirthdateFormat(PatientManagementInfo patientInfo, Errors errors) {
String birthDate = patientInfo.getBirthDateForDisplay();
boolean validBirthDateFormat = true;

if (!org.apache.commons.validator.GenericValidator.isBlankOrNull(birthDate)) {
validBirthDateFormat = birthDate.length() == 10;
// the regex matches ambiguous day and month or ambiguous day or completely
// formed date
if (validBirthDateFormat) {
validBirthDateFormat = birthDate.matches("(((" + AMBIGUOUS_DATE_HOLDER + "|\\d{2})/\\d{2})|"
+ AMBIGUOUS_DATE_HOLDER + "/(" + AMBIGUOUS_DATE_HOLDER + "|\\d{2}))/\\d{4}");
}

if (!validBirthDateFormat) {
errors.reject("error.birthdate.format", "error.birthdate.format");
}
}
}

private void setLastUpdatedTimeStamps(PatientManagementInfo patientInfo, Patient patient) {
String patientUpdate = patientInfo.getPatientLastUpdated();
if (!org.apache.commons.validator.GenericValidator.isBlankOrNull(patientUpdate)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.openelisglobal.common.util.ConfigurationProperties;
import org.openelisglobal.dataexchange.fhir.exception.FhirPersistanceException;
import org.openelisglobal.dataexchange.fhir.exception.FhirTransformationException;
import org.openelisglobal.dataexchange.fhir.service.FhirTransformService;
import org.openelisglobal.patient.action.IPatientUpdate.PatientUpdateStatus;
import org.openelisglobal.patient.action.bean.PatientManagementInfo;
import org.openelisglobal.patient.service.PatientService;
import org.openelisglobal.patient.validator.ValidatePatientInfo;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.StaleObjectStateException;
import org.openelisglobal.common.exception.LIMSRuntimeException;
import org.openelisglobal.common.log.LogEvent;
import org.openelisglobal.common.provider.query.PatientSearchResults;
import org.openelisglobal.common.rest.BaseRestController;
import org.openelisglobal.patient.valueholder.Patient;
import org.openelisglobal.patientidentity.service.PatientIdentityService;
Expand Down Expand Up @@ -52,10 +50,6 @@ public class PatientManagementRestController extends BaseRestController {
@Autowired
FhirTransformService fhirTransformService;

private static final String AMBIGUOUS_DATE_CHAR = ConfigurationProperties.getInstance()
.getPropertyValue(ConfigurationProperties.Property.AmbiguousDateHolder);
private static final String AMBIGUOUS_DATE_HOLDER = AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;

@PostMapping(value = "patient-management", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public void savepatient(HttpServletRequest request, @Validated(SamplePatientEntryForm.SamplePatientEntry.class) @RequestBody PatientManagementInfo patientInfo , BindingResult bindingResult)
Expand Down Expand Up @@ -101,7 +95,7 @@ public void savepatient(HttpServletRequest request, @Validated(SamplePatientEntr
private void preparePatientData(Errors errors ,HttpServletRequest request, PatientManagementInfo patientInfo,
Patient patient) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

validatePatientInfo(errors, patientInfo);
ValidatePatientInfo.validatePatientInfo(errors, patientInfo);
if (errors.hasErrors()) {
return;
}
Expand All @@ -122,64 +116,6 @@ private void preparePatientData(Errors errors ,HttpServletRequest request, Patie

}

private void validatePatientInfo(Errors errors, PatientManagementInfo patientInfo) {
boolean disallowDuplicateSubjectNumbers = ConfigurationProperties.getInstance()
.isPropertyValueEqual(ConfigurationProperties.Property.ALLOW_DUPLICATE_SUBJECT_NUMBERS, "false");
boolean disallowDuplicateNationalIds = ConfigurationProperties.getInstance()
.isPropertyValueEqual(ConfigurationProperties.Property.ALLOW_DUPLICATE_NATIONAL_IDS, "false");
if (disallowDuplicateSubjectNumbers || disallowDuplicateNationalIds) {
String newSTNumber = org.apache.commons.validator.GenericValidator.isBlankOrNull(patientInfo.getSTnumber()) ? null
: patientInfo.getSTnumber();
String newSubjectNumber = org.apache.commons.validator.GenericValidator.isBlankOrNull(patientInfo.getSubjectNumber()) ? null
: patientInfo.getSubjectNumber();
String newNationalId = org.apache.commons.validator.GenericValidator.isBlankOrNull(patientInfo.getNationalId()) ? null
: patientInfo.getNationalId();

List<PatientSearchResults> results = searchService.getSearchResults(null, null, newSTNumber, newSubjectNumber,
newNationalId, null, null, null, null, null);

if (!results.isEmpty()) {

for (PatientSearchResults result : results) {
if (!result.getPatientID().equals(patientInfo.getPatientPK())) {
if (disallowDuplicateSubjectNumbers && newSTNumber != null
&& newSTNumber.equals(result.getSTNumber())) {
errors.reject("error.duplicate.STNumber", null, null);
}
if (disallowDuplicateSubjectNumbers && newSubjectNumber != null
&& newSubjectNumber.equals(result.getSubjectNumber())) {
errors.reject("error.duplicate.subjectNumber", null, null);
}
if (disallowDuplicateNationalIds && newNationalId != null
&& newNationalId.equals(result.getNationalId())) {
errors.reject("error.duplicate.nationalId", null, null);
}
}
}
}
}
validateBirthdateFormat(patientInfo, errors);
}

private void validateBirthdateFormat(PatientManagementInfo patientInfo, Errors errors) {
String birthDate = patientInfo.getBirthDateForDisplay();
boolean validBirthDateFormat = true;

if (!org.apache.commons.validator.GenericValidator.isBlankOrNull(birthDate)) {
validBirthDateFormat = birthDate.length() == 10;
// the regex matches ambiguous day and month or ambiguous day or completely
// formed date
if (validBirthDateFormat) {
validBirthDateFormat = birthDate.matches("(((" + AMBIGUOUS_DATE_HOLDER + "|\\d{2})/\\d{2})|"
+ AMBIGUOUS_DATE_HOLDER + "/(" + AMBIGUOUS_DATE_HOLDER + "|\\d{2}))/\\d{4}");
}

if (!validBirthDateFormat) {
errors.reject("error.birthdate.format", "error.birthdate.format");
}
}
}

private void copyFormBeanToValueHolders(PatientManagementInfo patientInfo, Patient patient)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
PropertyUtils.copyProperties(patient, patientInfo);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.openelisglobal.patient.validator;

import java.util.List;

import org.apache.commons.validator.GenericValidator;
import org.openelisglobal.common.provider.query.PatientSearchResults;
import org.openelisglobal.common.util.ConfigurationProperties;
import org.openelisglobal.patient.action.bean.PatientManagementInfo;
import org.openelisglobal.search.service.SearchResultsService;
import org.openelisglobal.spring.util.SpringContext;
import org.springframework.validation.Errors;

public class ValidatePatientInfo {

private static final String AMBIGUOUS_DATE_CHAR = ConfigurationProperties.getInstance()
.getPropertyValue(ConfigurationProperties.Property.AmbiguousDateHolder);
private static final String AMBIGUOUS_DATE_HOLDER = AMBIGUOUS_DATE_CHAR + AMBIGUOUS_DATE_CHAR;

public static void validatePatientInfo(Errors errors, PatientManagementInfo patientInfo) {
boolean disallowDuplicateSubjectNumbers = ConfigurationProperties.getInstance()
.isPropertyValueEqual(ConfigurationProperties.Property.ALLOW_DUPLICATE_SUBJECT_NUMBERS, "false");
boolean disallowDuplicateNationalIds = ConfigurationProperties.getInstance()
.isPropertyValueEqual(ConfigurationProperties.Property.ALLOW_DUPLICATE_NATIONAL_IDS, "false");
if (disallowDuplicateSubjectNumbers || disallowDuplicateNationalIds) {
String newSTNumber = GenericValidator.isBlankOrNull(patientInfo.getSTnumber()) ? null
: patientInfo.getSTnumber();
String newSubjectNumber = GenericValidator.isBlankOrNull(patientInfo.getSubjectNumber()) ? null
: patientInfo.getSubjectNumber();
String newNationalId = GenericValidator.isBlankOrNull(patientInfo.getNationalId()) ? null
: patientInfo.getNationalId();

List<PatientSearchResults> results = SpringContext.getBean(SearchResultsService.class).getSearchResults(null, null, newSTNumber, newSubjectNumber,
newNationalId, null, null, null, null, null);

PatientSearchResults existingResult = null ;

if(!GenericValidator.isBlankOrNull(patientInfo.getPatientPK())){
existingResult = SpringContext.getBean(SearchResultsService.class).getSearchResults(null, null, null, null,
null, null, patientInfo.getPatientPK(), null, null, null).get(0);
}

if (!results.isEmpty()) {

for (PatientSearchResults result : results) {
if (!result.getPatientID().equals(patientInfo.getPatientPK())) {
if (disallowDuplicateSubjectNumbers && newSTNumber != null
&& newSTNumber.equals(result.getSTNumber())) {
if (existingResult == null
|| (existingResult != null && !existingResult.getSTNumber().equals(newSTNumber))) {
errors.reject("error.duplicate.STNumber", null, null);
}
}
if (disallowDuplicateSubjectNumbers && newSubjectNumber != null
&& newSubjectNumber.equals(result.getSubjectNumber())) {

if (existingResult == null || (existingResult != null
&& !existingResult.getSubjectNumber().equals(newSubjectNumber))) {
errors.reject("error.duplicate.subjectNumber", null, null);
}
}
if (disallowDuplicateNationalIds && newNationalId != null
&& newNationalId.equals(result.getNationalId())) {

if (existingResult == null || (existingResult != null
&& !existingResult.getNationalId().equals(newNationalId))) {
errors.reject("error.duplicate.nationalId", null, null);
}
}
}
}
}
}
validateBirthdateFormat(patientInfo, errors);
}

private static void validateBirthdateFormat(PatientManagementInfo patientInfo, Errors errors) {
String birthDate = patientInfo.getBirthDateForDisplay();
boolean validBirthDateFormat = true;

if (!org.apache.commons.validator.GenericValidator.isBlankOrNull(birthDate)) {
validBirthDateFormat = birthDate.length() == 10;
// the regex matches ambiguous day and month or ambiguous day or completely
// formed date
if (validBirthDateFormat) {
validBirthDateFormat = birthDate.matches("(((" + AMBIGUOUS_DATE_HOLDER + "|\\d{2})/\\d{2})|"
+ AMBIGUOUS_DATE_HOLDER + "/(" + AMBIGUOUS_DATE_HOLDER + "|\\d{2}))/\\d{4}");
}

if (!validBirthDateFormat) {
errors.reject("error.birthdate.format", "error.birthdate.format");
}
}
}
}
Loading

0 comments on commit ff117b5

Please sign in to comment.